From 0738ec6a540b1f8e606212718c428192151312af Mon Sep 17 00:00:00 2001 From: Ilmir Usmanov Date: Wed, 24 Sep 2014 15:30:37 +0400 Subject: [PATCH] Add generation of prop_setter. --- src/libintstructs/hash-table.h | 150 ++++++++ src/libintstructs/stack.h | 6 +- src/libjsparser/parser.c | 570 +++++++++++++++++------------- src/liboptimizer/deserializer.c | 10 +- src/liboptimizer/deserializer.h | 2 + src/liboptimizer/pretty-printer.c | 1 + src/liboptimizer/serializer.c | 7 + src/liboptimizer/serializer.h | 7 +- tests/jerry/object_literal.js | 27 +- 9 files changed, 510 insertions(+), 270 deletions(-) create mode 100644 src/libintstructs/hash-table.h diff --git a/src/libintstructs/hash-table.h b/src/libintstructs/hash-table.h new file mode 100644 index 000000000..b112d95c4 --- /dev/null +++ b/src/libintstructs/hash-table.h @@ -0,0 +1,150 @@ +/* Copyright 2014 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + This file contains macros to create and manipulate hash-tables. + In order to define a hash use HASH_TABLE or STATIC_HASH_TABLE macro. + DO NOT FORGET to define KEY_TYPE##_hash and KEY_TYPE##_equal functions, they will be used + for internal purposes. + Before using the hash initialize it by calling HASH_INIT macro. + To insert a key-value pair, use HASH_INSERT macro. + To lookup a value by the key, use HASH_LOOKUP macro. + After using the hash, delete it by calling HASH_FREE macro. +*/ +#ifndef HASH_TABLE_H +#define HASH_TABLE_H + +#define DEFINE_BACKET_TYPE(NAME, KEY_TYPE, VALUE_TYPE) \ +typedef struct \ +{ \ + KEY_TYPE key; \ + VALUE_TYPE value; \ +} \ +__packed \ +NAME##_backet; + +#define DEFINE_HASH_TYPE(NAME, KEY_TYPE, VALUE_TYPE) \ +typedef struct \ +{ \ + uint8_t size; \ + NAME##_backet_stack *backets; \ +} \ +__packed \ +NAME##_hash_table; + +#define HASH_INIT(NAME, SIZE) \ +do { \ + NAME.size = SIZE; \ + size_t size = mem_heap_recommend_allocation_size (SIZE * sizeof (NAME##_backet_stack)); \ + NAME.backets = (NAME##_backet_stack *) mem_heap_alloc_block (size, MEM_HEAP_ALLOC_SHORT_TERM); \ + __memset (NAME.backets, 0, size); \ +} while (0); + +#define HASH_FREE(NAME) \ +do { \ + for (uint8_t i = 0; i < NAME.size; i++) { \ + if (NAME.backets[i].length != 0) { \ + mem_heap_free_block ((uint8_t *) NAME.backets[i].data); \ + } \ + } \ + mem_heap_free_block ((uint8_t *) NAME.backets); \ +} while (0) + +#define DEFINE_HASH_INSERT(NAME, KEY_TYPE, VALUE_TYPE) \ +static void hash_insert_##NAME (KEY_TYPE key, VALUE_TYPE value) __unused; \ +static void hash_insert_##NAME (KEY_TYPE key, VALUE_TYPE value) { \ + NAME##_backet backet = (NAME##_backet) { .key = key, .value = value }; \ + uint8_t hash = KEY_TYPE##_hash (key); \ + JERRY_ASSERT (hash < NAME.size); \ + JERRY_ASSERT (NAME.backets != NULL); \ + if (NAME.backets[hash].length == 0) \ + { \ + size_t stack_size = mem_heap_recommend_allocation_size (0); \ + NAME.backets[hash].data = (NAME##_backet *) mem_heap_alloc_block \ + (stack_size, MEM_HEAP_ALLOC_SHORT_TERM); \ + NAME.backets[hash].current = 0; \ + NAME.backets[hash].length = (__typeof__ (NAME.backets[hash].length)) \ + (stack_size / sizeof (NAME##_backet)); \ + } \ + else if (NAME.backets[hash].current == NAME.backets[hash].length) \ + { \ + size_t old_size = NAME.backets[hash].length * sizeof (NAME##_backet); \ + size_t temp1_size = mem_heap_recommend_allocation_size ( \ + (size_t) (sizeof (NAME##_backet))); \ + size_t new_size = mem_heap_recommend_allocation_size ( \ + (size_t) (temp1_size + old_size)); \ + NAME##_backet *temp1 = (NAME##_backet *) mem_heap_alloc_block \ + (temp1_size, MEM_HEAP_ALLOC_SHORT_TERM); \ + NAME##_backet *temp2 = (NAME##_backet *) mem_heap_alloc_block \ + (old_size, MEM_HEAP_ALLOC_SHORT_TERM); \ + if (temp2 == NULL) \ + { \ + mem_heap_print (true, false, true); \ + JERRY_UNREACHABLE (); \ + } \ + __memcpy (temp2, NAME.backets[hash].data, old_size); \ + mem_heap_free_block ((uint8_t *) NAME.backets[hash].data); \ + mem_heap_free_block ((uint8_t *) temp1); \ + NAME.backets[hash].data = (NAME##_backet *) mem_heap_alloc_block \ + (new_size, MEM_HEAP_ALLOC_SHORT_TERM); \ + __memcpy (NAME.backets[hash].data, temp2, old_size); \ + mem_heap_free_block ((uint8_t *) temp2); \ + NAME.backets[hash].length = (__typeof__ (NAME.backets[hash].length)) \ + (new_size / sizeof (NAME##_backet)); \ + } \ + NAME.backets[hash].data[NAME.backets[hash].current++] = backet; \ +} + +#define HASH_INSERT(NAME, KEY, VALUE) \ +do { \ + hash_insert_##NAME (KEY, VALUE); \ +} while (0) + +#define DEFINE_HASH_LOOKUP(NAME, KEY_TYPE, VALUE_TYPE) \ +static VALUE_TYPE *lookup_##NAME (KEY_TYPE key) __unused; \ +static VALUE_TYPE *lookup_##NAME (KEY_TYPE key) { \ + uint8_t hash = KEY_TYPE##_hash (key); \ + JERRY_ASSERT (hash < NAME.size); \ + if (NAME.backets[hash].length == 0) { \ + return NULL; \ + } \ + for (size_t i = 0; i < NAME.backets[hash].current; i++) { \ + if (KEY_TYPE##_equal (NAME.backets[hash].data[i].key, key)) { \ + return &NAME.backets[hash].data[i].value; \ + } \ + } \ + return NULL; \ +} + +#define HASH_LOOKUP(NAME, KEY) \ +lookup_##NAME (KEY) + +#define HASH_TABLE(NAME, KEY_TYPE, VALUE_TYPE) \ +DEFINE_BACKET_TYPE (NAME, KEY_TYPE, VALUE_TYPE) \ +DEFINE_STACK_TYPE (NAME##_backet, uint8_t, NAME##_backet) \ +DEFINE_HASH_TYPE (NAME, KEY_TYPE, VALUE_TYPE) \ +NAME##_hash_table NAME; \ +DEFINE_HASH_INSERT (NAME, KEY_TYPE, VALUE_TYPE) \ +DEFINE_HASH_LOOKUP (NAME, KEY_TYPE, VALUE_TYPE) + +#define STATIC_HASH_TABLE(NAME, KEY_TYPE, VALUE_TYPE) \ +DEFINE_BACKET_TYPE (NAME, KEY_TYPE, VALUE_TYPE) \ +DEFINE_STACK_TYPE (NAME##_backet, uint8_t, NAME##_backet) \ +DEFINE_HASH_TYPE (NAME, KEY_TYPE, VALUE_TYPE) \ +static NAME##_hash_table NAME; \ +DEFINE_HASH_INSERT (NAME, KEY_TYPE, VALUE_TYPE) \ +DEFINE_HASH_LOOKUP (NAME, KEY_TYPE, VALUE_TYPE) + +#endif /* HASH_TABLE_H */ diff --git a/src/libintstructs/stack.h b/src/libintstructs/stack.h index 38224f409..3ea4d934b 100644 --- a/src/libintstructs/stack.h +++ b/src/libintstructs/stack.h @@ -130,9 +130,9 @@ increase_##NAME##_stack_size (__typeof__ (NAME.length) elements_count) { \ } #define DEFINE_DECREASE_STACE_SIZE(NAME) \ -static void decrease_##NAME##_stack_size (uint8_t) __unused; \ +static void decrease_##NAME##_stack_size (__typeof__ (NAME.length)) __unused; \ static void \ -decrease_##NAME##_stack_size (uint8_t elements_count) { \ +decrease_##NAME##_stack_size (__typeof__ (NAME.length) elements_count) { \ JERRY_ASSERT (NAME.current - elements_count >= NAME##_global_size); \ NAME.current = (__typeof__ (NAME.current)) (NAME.current - elements_count); \ } @@ -150,7 +150,7 @@ do { \ } while (0) #define STACK_DROP(NAME, I) \ -do { decrease_##NAME##_stack_size (I); } while (0) +do { decrease_##NAME##_stack_size ((__typeof__(NAME.current))(I)); } while (0) #define STACK_CLEAN(NAME) \ STACK_DROP (NAME, NAME.current - NAME##_global_size); diff --git a/src/libjsparser/parser.c b/src/libjsparser/parser.c index a4c1ebc8e..cc7b0cfc4 100644 --- a/src/libjsparser/parser.c +++ b/src/libjsparser/parser.c @@ -21,6 +21,8 @@ #include "serializer.h" #include "interpreter.h" #include "stack.h" +#include "hash-table.h" +#include "deserializer.h" #define INVALID_VALUE 255 #define INTRINSICS_COUNT 1 @@ -135,10 +137,125 @@ JERRY_ASSERT (IDX.current == IDX_current + 1); #define STACK_CHECK_USAGE_LHS() ; #endif +static uint8_t lp_string_hash (lp_string); +STATIC_HASH_TABLE (intrinsics, lp_string, intrinsic_dumper) + +#define LAST_OPCODE_IS(OP) (deserialize_opcode((opcode_counter_t)(OPCODE_COUNTER()-1)).op_idx == __op__idx_##OP) + JERRY_STATIC_ASSERT (sizeof (idx_t) == sizeof (uint8_t)); JERRY_STATIC_ASSERT (sizeof (opcode_counter_t) == sizeof (uint16_t)); +static void skip_newlines (void); +#define NEXT(TYPE) \ +do { skip_newlines (); parse_##TYPE (); } while (0) + +#define DUMP_VOID_OPCODE(GETOP) \ +do { \ + OPCODE()=getop_##GETOP (); \ + serializer_dump_opcode (OPCODE()); \ + OPCODE_COUNTER()++; \ +} while (0) + +#define DUMP_OPCODE_1(GETOP, OP1) \ +do { \ + JERRY_ASSERT (0+OP1 <= 255); \ + OPCODE()=getop_##GETOP ((idx_t) (OP1)); \ + serializer_dump_opcode (OPCODE()); \ + OPCODE_COUNTER()++; \ +} while (0) + +#define DUMP_OPCODE_2(GETOP, OP1, OP2) \ +do { \ + JERRY_ASSERT (0+OP1 <= 255); \ + JERRY_ASSERT (0+OP2 <= 255); \ + OPCODE()=getop_##GETOP ((idx_t) (OP1), (idx_t) (OP2)); \ + serializer_dump_opcode (OPCODE()); \ + OPCODE_COUNTER()++; \ +} while (0) + +#define DUMP_OPCODE_3(GETOP, OP1, OP2, OP3) \ +do { \ + JERRY_ASSERT (0+OP1 <= 255); \ + JERRY_ASSERT (0+OP2 <= 255); \ + JERRY_ASSERT (0+OP3 <= 255); \ + OPCODE()=getop_##GETOP ((idx_t) (OP1), (idx_t) (OP2), (idx_t) (OP3)); \ + serializer_dump_opcode (OPCODE()); \ + OPCODE_COUNTER()++; \ +} while (0) + +#define REWRITE_VOID_OPCODE(OC, GETOP) \ +do { \ + OPCODE()=getop_##GETOP (); \ + serializer_rewrite_opcode (OC, OPCODE()); \ +} while (0) + +#define REWRITE_OPCODE_1(OC, GETOP, OP1) \ +do { \ + JERRY_ASSERT (0+OP1 <= 255); \ + OPCODE()=getop_##GETOP ((idx_t) (OP1)); \ + serializer_rewrite_opcode (OC, OPCODE()); \ +} while (0) + +#define REWRITE_OPCODE_2(OC, GETOP, OP1, OP2) \ +do { \ + JERRY_ASSERT (0+OP1 <= 255); \ + JERRY_ASSERT (0+OP2 <= 255); \ + OPCODE()=getop_##GETOP ((idx_t) (OP1), (idx_t) (OP2)); \ + serializer_rewrite_opcode (OC, OPCODE()); \ +} while (0) + +#define REWRITE_OPCODE_3(OC, GETOP, OP1, OP2, OP3) \ +do { \ + JERRY_ASSERT (0+OP1 <= 255); \ + JERRY_ASSERT (0+OP2 <= 255); \ + JERRY_ASSERT (0+OP3 <= 255); \ + OPCODE()=getop_##GETOP ((idx_t) (OP1), (idx_t) (OP2), (idx_t) (OP3)); \ + serializer_rewrite_opcode (OC, OPCODE()); \ +} while (0) + +#define REWRITE_COND_JMP(OC, GETOP, DIFF) \ +do { \ + JERRY_ASSERT (0+DIFF <= 256*256 - 1); \ + STACK_DECLARE_USAGE (IDX); \ + JERRY_STATIC_ASSERT (sizeof (idx_t) == 1); \ + STACK_PUSH (IDX, (idx_t) ((DIFF) >> JERRY_BITSINBYTE)); \ + STACK_PUSH (IDX, (idx_t) ((DIFF) & ((1 << JERRY_BITSINBYTE) - 1))); \ + JERRY_ASSERT ((DIFF) == calc_opcode_counter_from_idx_idx (STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1))); \ + OPCODE()=getop_##GETOP (STACK_HEAD (IDX, 3), STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1)); \ + serializer_rewrite_opcode (OC, OPCODE()); \ + STACK_DROP (IDX, 2); \ + STACK_CHECK_USAGE (IDX); \ +} while (0) + +#define REWRITE_JMP(OC, GETOP, DIFF) \ +do { \ + JERRY_ASSERT (0+DIFF <= 256*256 - 1); \ + STACK_DECLARE_USAGE (IDX) \ + JERRY_STATIC_ASSERT (sizeof (idx_t) == 1); \ + STACK_PUSH (IDX, (idx_t) ((DIFF) >> JERRY_BITSINBYTE)); \ + STACK_PUSH (IDX, (idx_t) ((DIFF) & ((1 << JERRY_BITSINBYTE) - 1))); \ + JERRY_ASSERT ((DIFF) == calc_opcode_counter_from_idx_idx (STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1))); \ + OPCODE()=getop_##GETOP (STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1)); \ + serializer_rewrite_opcode (OC, OPCODE()); \ + STACK_DROP (IDX, 2); \ + STACK_CHECK_USAGE (IDX); \ +} while (0) + +#define REWRITE_TRY(OC) \ +do { \ + STACK_DECLARE_USAGE (IDX) \ + JERRY_STATIC_ASSERT (sizeof (idx_t) == 1); \ + STACK_PUSH (IDX, (idx_t) ((OPCODE_COUNTER ()) >> JERRY_BITSINBYTE)); \ + STACK_PUSH (IDX, (idx_t) ((OPCODE_COUNTER ()) & ((1 << JERRY_BITSINBYTE) - 1))); \ + JERRY_ASSERT ((OPCODE_COUNTER ()) \ + == calc_opcode_counter_from_idx_idx (STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1))); \ + OPCODE()=getop_try (STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1)); \ + serializer_rewrite_opcode ((OC), OPCODE()); \ + STACK_DROP (IDX, 2); \ + STACK_CHECK_USAGE (IDX); \ +} while (0) + typedef enum { AL_FUNC_DECL, @@ -150,131 +267,6 @@ typedef enum } argument_list_type; -#define DEFINE_BACKET_TYPE(NAME, KEY_TYPE, VALUE_TYPE) \ -typedef struct \ -{ \ - KEY_TYPE key; \ - VALUE_TYPE value; \ -} \ -__packed \ -NAME##_backet; - -#define DEFINE_HASH_TYPE(NAME, KEY_TYPE, VALUE_TYPE) \ -typedef struct \ -{ \ - uint8_t size; \ - NAME##_backet_stack *backets; \ -} \ -__packed \ -NAME##_hash_table; - -#define HASH_INIT(NAME, SIZE) \ -do { \ - NAME.size = SIZE; \ - size_t size = mem_heap_recommend_allocation_size (SIZE * sizeof (NAME##_backet_stack)); \ - NAME.backets = (NAME##_backet_stack *) mem_heap_alloc_block (size, MEM_HEAP_ALLOC_SHORT_TERM); \ - __memset (NAME.backets, 0, size); \ -} while (0); - -#define HASH_FREE(NAME) \ -do { \ - for (uint8_t i = 0; i < NAME.size; i++) { \ - if (NAME.backets[i].length != 0) { \ - mem_heap_free_block ((uint8_t *) NAME.backets[i].data); \ - } \ - } \ - mem_heap_free_block ((uint8_t *) NAME.backets); \ -} while (0) - -#define DEFINE_HASH_INSERT(NAME, KEY_TYPE, VALUE_TYPE) \ -static void hash_insert_##NAME (KEY_TYPE key, VALUE_TYPE value) __unused; \ -static void hash_insert_##NAME (KEY_TYPE key, VALUE_TYPE value) { \ - NAME##_backet backet = (NAME##_backet) { .key = key, .value = value }; \ - uint8_t hash = KEY_TYPE##_hash (key); \ - JERRY_ASSERT (hash < NAME.size); \ - JERRY_ASSERT (NAME.backets != NULL); \ - if (NAME.backets[hash].length == 0) \ - { \ - size_t stack_size = mem_heap_recommend_allocation_size (0); \ - NAME.backets[hash].data = (NAME##_backet *) mem_heap_alloc_block \ - (stack_size, MEM_HEAP_ALLOC_SHORT_TERM); \ - NAME.backets[hash].current = 0; \ - NAME.backets[hash].length = (__typeof__ (NAME.backets[hash].length)) \ - (stack_size / sizeof (NAME##_backet)); \ - } \ - else if (NAME.backets[hash].current == NAME.backets[hash].length) \ - { \ - size_t old_size = NAME.backets[hash].length * sizeof (NAME##_backet); \ - size_t temp1_size = mem_heap_recommend_allocation_size ( \ - (size_t) (sizeof (NAME##_backet))); \ - size_t new_size = mem_heap_recommend_allocation_size ( \ - (size_t) (temp1_size + old_size)); \ - NAME##_backet *temp1 = (NAME##_backet *) mem_heap_alloc_block \ - (temp1_size, MEM_HEAP_ALLOC_SHORT_TERM); \ - NAME##_backet *temp2 = (NAME##_backet *) mem_heap_alloc_block \ - (old_size, MEM_HEAP_ALLOC_SHORT_TERM); \ - if (temp2 == NULL) \ - { \ - mem_heap_print (true, false, true); \ - JERRY_UNREACHABLE (); \ - } \ - __memcpy (temp2, NAME.backets[hash].data, old_size); \ - mem_heap_free_block ((uint8_t *) NAME.backets[hash].data); \ - mem_heap_free_block ((uint8_t *) temp1); \ - NAME.backets[hash].data = (NAME##_backet *) mem_heap_alloc_block \ - (new_size, MEM_HEAP_ALLOC_SHORT_TERM); \ - __memcpy (NAME.backets[hash].data, temp2, old_size); \ - mem_heap_free_block ((uint8_t *) temp2); \ - NAME.backets[hash].length = (__typeof__ (NAME.backets[hash].length)) \ - (new_size / sizeof (NAME##_backet)); \ - } \ - NAME.backets[hash].data[NAME.backets[hash].current++] = backet; \ -} - -#define HASH_INSERT(NAME, KEY, VALUE) \ -do { \ - hash_insert_##NAME (KEY, VALUE); \ -} while (0) - -#define DEFINE_HASH_LOOKUP(NAME, KEY_TYPE, VALUE_TYPE) \ -static VALUE_TYPE *lookup_##NAME (KEY_TYPE key) __unused; \ -static VALUE_TYPE *lookup_##NAME (KEY_TYPE key) { \ - uint8_t hash = KEY_TYPE##_hash (key); \ - JERRY_ASSERT (hash < NAME.size); \ - if (NAME.backets[hash].length == 0) { \ - return NULL; \ - } \ - for (size_t i = 0; i < NAME.backets[hash].current; i++) { \ - if (KEY_TYPE##_equal (NAME.backets[hash].data[i].key, key)) { \ - return &NAME.backets[hash].data[i].value; \ - } \ - } \ - return NULL; \ -} - -#define HASH_LOOKUP(NAME, KEY) \ -lookup_##NAME (KEY) - -#define HASH_TABLE(NAME, KEY_TYPE, VALUE_TYPE) \ -DEFINE_BACKET_TYPE (NAME, KEY_TYPE, VALUE_TYPE) \ -DEFINE_STACK_TYPE (NAME##_backet, uint8_t, NAME##_backet) \ -DEFINE_HASH_TYPE (NAME, KEY_TYPE, VALUE_TYPE) \ -NAME##_hash_table NAME; \ -DEFINE_HASH_INSERT (NAME, KEY_TYPE, VALUE_TYPE) \ -DEFINE_HASH_LOOKUP (NAME, KEY_TYPE, VALUE_TYPE) - -#define STATIC_HASH_TABLE(NAME, KEY_TYPE, VALUE_TYPE) \ -DEFINE_BACKET_TYPE (NAME, KEY_TYPE, VALUE_TYPE) \ -DEFINE_STACK_TYPE (NAME##_backet, uint8_t, NAME##_backet) \ -DEFINE_HASH_TYPE (NAME, KEY_TYPE, VALUE_TYPE) \ -static NAME##_hash_table NAME; \ -DEFINE_HASH_INSERT (NAME, KEY_TYPE, VALUE_TYPE) \ -DEFINE_HASH_LOOKUP (NAME, KEY_TYPE, VALUE_TYPE) - -static uint8_t lp_string_hash (lp_string); - -STATIC_HASH_TABLE (intrinsics, lp_string, intrinsic_dumper) - static void parse_expression (void); static void parse_statement (void); static void parse_assignment_expression (void); @@ -461,109 +453,6 @@ token_after_newlines_must_be_keyword (keyword kw) } } -#define NEXT(TYPE) \ -do { skip_newlines (); parse_##TYPE (); } while (0) - -#define DUMP_VOID_OPCODE(GETOP) \ -do { \ - OPCODE()=getop_##GETOP (); \ - serializer_dump_opcode (OPCODE()); \ - OPCODE_COUNTER()++; \ -} while (0) - -#define DUMP_OPCODE_1(GETOP, OP1) \ -do { \ - JERRY_ASSERT (0+OP1 <= 255); \ - OPCODE()=getop_##GETOP ((idx_t) (OP1)); \ - serializer_dump_opcode (OPCODE()); \ - OPCODE_COUNTER()++; \ -} while (0) - -#define DUMP_OPCODE_2(GETOP, OP1, OP2) \ -do { \ - JERRY_ASSERT (0+OP1 <= 255); \ - JERRY_ASSERT (0+OP2 <= 255); \ - OPCODE()=getop_##GETOP ((idx_t) (OP1), (idx_t) (OP2)); \ - serializer_dump_opcode (OPCODE()); \ - OPCODE_COUNTER()++; \ -} while (0) - -#define DUMP_OPCODE_3(GETOP, OP1, OP2, OP3) \ -do { \ - JERRY_ASSERT (0+OP1 <= 255); \ - JERRY_ASSERT (0+OP2 <= 255); \ - JERRY_ASSERT (0+OP3 <= 255); \ - OPCODE()=getop_##GETOP ((idx_t) (OP1), (idx_t) (OP2), (idx_t) (OP3)); \ - serializer_dump_opcode (OPCODE()); \ - OPCODE_COUNTER()++; \ -} while (0) - -#define REWRITE_OPCODE_1(OC, GETOP, OP1) \ -do { \ - JERRY_ASSERT (0+OP1 <= 255); \ - OPCODE()=getop_##GETOP ((idx_t) (OP1)); \ - serializer_rewrite_opcode (OC, OPCODE()); \ -} while (0) - -#define REWRITE_OPCODE_2(OC, GETOP, OP1, OP2) \ -do { \ - JERRY_ASSERT (0+OP1 <= 255); \ - JERRY_ASSERT (0+OP2 <= 255); \ - OPCODE()=getop_##GETOP ((idx_t) (OP1), (idx_t) (OP2)); \ - serializer_rewrite_opcode (OC, OPCODE()); \ -} while (0) - -#define REWRITE_OPCODE_3(OC, GETOP, OP1, OP2, OP3) \ -do { \ - JERRY_ASSERT (0+OP1 <= 255); \ - JERRY_ASSERT (0+OP2 <= 255); \ - JERRY_ASSERT (0+OP3 <= 255); \ - OPCODE()=getop_##GETOP ((idx_t) (OP1), (idx_t) (OP2), (idx_t) (OP3)); \ - serializer_rewrite_opcode (OC, OPCODE()); \ -} while (0) - -#define REWRITE_COND_JMP(OC, GETOP, DIFF) \ -do { \ - JERRY_ASSERT (0+DIFF <= 256*256 - 1); \ - STACK_DECLARE_USAGE (IDX); \ - JERRY_STATIC_ASSERT (sizeof (idx_t) == 1); \ - STACK_PUSH (IDX, (idx_t) ((DIFF) >> JERRY_BITSINBYTE)); \ - STACK_PUSH (IDX, (idx_t) ((DIFF) & ((1 << JERRY_BITSINBYTE) - 1))); \ - JERRY_ASSERT ((DIFF) == calc_opcode_counter_from_idx_idx (STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1))); \ - OPCODE()=getop_##GETOP (STACK_HEAD (IDX, 3), STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1)); \ - serializer_rewrite_opcode (OC, OPCODE()); \ - STACK_DROP (IDX, 2); \ - STACK_CHECK_USAGE (IDX); \ -} while (0) - -#define REWRITE_JMP(OC, GETOP, DIFF) \ -do { \ - JERRY_ASSERT (0+DIFF <= 256*256 - 1); \ - STACK_DECLARE_USAGE (IDX) \ - JERRY_STATIC_ASSERT (sizeof (idx_t) == 1); \ - STACK_PUSH (IDX, (idx_t) ((DIFF) >> JERRY_BITSINBYTE)); \ - STACK_PUSH (IDX, (idx_t) ((DIFF) & ((1 << JERRY_BITSINBYTE) - 1))); \ - JERRY_ASSERT ((DIFF) == calc_opcode_counter_from_idx_idx (STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1))); \ - OPCODE()=getop_##GETOP (STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1)); \ - serializer_rewrite_opcode (OC, OPCODE()); \ - STACK_DROP (IDX, 2); \ - STACK_CHECK_USAGE (IDX); \ -} while (0) - -#define REWRITE_TRY(OC) \ -do { \ - STACK_DECLARE_USAGE (IDX) \ - JERRY_STATIC_ASSERT (sizeof (idx_t) == 1); \ - STACK_PUSH (IDX, (idx_t) ((OPCODE_COUNTER ()) >> JERRY_BITSINBYTE)); \ - STACK_PUSH (IDX, (idx_t) ((OPCODE_COUNTER ()) & ((1 << JERRY_BITSINBYTE) - 1))); \ - JERRY_ASSERT ((OPCODE_COUNTER ()) \ - == calc_opcode_counter_from_idx_idx (STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1))); \ - OPCODE()=getop_try (STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1)); \ - serializer_rewrite_opcode ((OC), OPCODE()); \ - STACK_DROP (IDX, 2); \ - STACK_CHECK_USAGE (IDX); \ -} while (0) - static void integer_zero (void) { @@ -1815,11 +1704,12 @@ PARSE_OF (logical_or_expression, logical_and_expression, DOUBLE_OR, logical_or) : logical_or_expression (LT!* '?' LT!* assignment_expression LT!* ':' LT!* assignment_expression)? ; */ static void -parse_conditional_expression (bool *was_conditional) +parse_conditional_expression (void) { // IDX expr, res, lhs STACK_DECLARE_USAGE (IDX) STACK_DECLARE_USAGE (U16) + STACK_DECLARE_USAGE (U8) parse_logical_or_expression (); @@ -1844,7 +1734,7 @@ parse_conditional_expression (bool *was_conditional) DUMP_OPCODE_3 (assignment, STACK_HEAD (IDX, 2), OPCODE_ARG_TYPE_VARIABLE, STACK_HEAD (IDX, 1)); REWRITE_JMP (STACK_HEAD (U16, 1), jmp_down, OPCODE_COUNTER () - STACK_HEAD (U16, 1)); - *was_conditional = true; + STACK_HEAD (U8, 1) = 1; STACK_HEAD (IDX, 3) = STACK_HEAD (IDX, 2); STACK_DROP (IDX, 2); } @@ -1854,6 +1744,7 @@ parse_conditional_expression (bool *was_conditional) } STACK_CHECK_USAGE (U16); + STACK_CHECK_USAGE (U8); STACK_CHECK_USAGE_LHS (); } @@ -1866,87 +1757,269 @@ parse_assignment_expression (void) { // IDX lhs, rhs; STACK_DECLARE_USAGE (IDX) - bool was_conditional = false; + STACK_DECLARE_USAGE (U16); + STACK_DECLARE_USAGE (U8); + STACK_DECLARE_USAGE (ops); - parse_conditional_expression (&was_conditional); - if (was_conditional) + STACK_PUSH (U8, 0); + + parse_conditional_expression (); + if (STACK_HEAD (U8, 1)) { + STACK_DROP (U8, 1); goto cleanup; } + /* Rewrite prop_getter with nop and generate prop_setter in constructions like: + a.b = c; */ + if (LAST_OPCODE_IS (prop_getter)) + { + STACK_PUSH (U16, (opcode_counter_t) (OPCODE_COUNTER () - 1)); + STACK_HEAD (U8, 1) = 1; + } + skip_newlines (); switch (TOK ().type) { case TOK_EQ: { - NEXT (assignment_expression); - DUMP_OPCODE_3 (assignment, STACK_HEAD (IDX, 2), OPCODE_ARG_TYPE_VARIABLE, STACK_HEAD (IDX, 1)); + if (STACK_HEAD (U8, 1)) + { + STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 1))); + JERRY_ASSERT (STACK_HEAD (ops, 1).op_idx == __op__idx_prop_getter); + serializer_set_writing_position (--OPCODE_COUNTER ()); + NEXT (assignment_expression); + DUMP_OPCODE_3 (prop_setter, STACK_HEAD (ops, 1).data.prop_getter.obj, + STACK_HEAD (ops, 1).data.prop_getter.prop, STACK_HEAD (IDX, 1)); + STACK_DROP (ops, 1); + STACK_DROP (U16, 1); + } + else + { + NEXT (assignment_expression); + DUMP_OPCODE_3 (assignment, STACK_HEAD (IDX, 2), OPCODE_ARG_TYPE_VARIABLE, + STACK_HEAD (IDX, 1)); + } break; } case TOK_MULT_EQ: { NEXT (assignment_expression); - DUMP_OPCODE_3 (multiplication, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1)); + if (STACK_HEAD (U8, 1)) + { + STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); + DUMP_OPCODE_3 (multiplication, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + DUMP_OPCODE_3 (prop_setter, STACK_HEAD (ops, 1).data.prop_getter.obj, + STACK_HEAD (ops, 1).data.prop_getter.prop, STACK_HEAD (IDX, 2)); + STACK_DROP (ops, 1); + STACK_DROP (U16, 1); + } + else + { + DUMP_OPCODE_3 (multiplication, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + } break; } case TOK_DIV_EQ: { NEXT (assignment_expression); - DUMP_OPCODE_3 (division, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1)); + if (STACK_HEAD (U8, 1)) + { + STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); + DUMP_OPCODE_3 (division, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + DUMP_OPCODE_3 (prop_setter, STACK_HEAD (ops, 1).data.prop_getter.obj, + STACK_HEAD (ops, 1).data.prop_getter.prop, STACK_HEAD (IDX, 2)); + STACK_DROP (ops, 1); + STACK_DROP (U16, 1); + } + else + { + DUMP_OPCODE_3 (division, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + } break; } case TOK_MOD_EQ: { NEXT (assignment_expression); - DUMP_OPCODE_3 (remainder, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1)); + if (STACK_HEAD (U8, 1)) + { + STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); + DUMP_OPCODE_3 (remainder, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + DUMP_OPCODE_3 (prop_setter, STACK_HEAD (ops, 1).data.prop_getter.obj, + STACK_HEAD (ops, 1).data.prop_getter.prop, STACK_HEAD (IDX, 2)); + STACK_DROP (ops, 1); + STACK_DROP (U16, 1); + } + else + { + DUMP_OPCODE_3 (remainder, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + } break; } case TOK_PLUS_EQ: { NEXT (assignment_expression); - DUMP_OPCODE_3 (addition, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1)); + if (STACK_HEAD (U8, 1)) + { + STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); + DUMP_OPCODE_3 (addition, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + DUMP_OPCODE_3 (prop_setter, STACK_HEAD (ops, 1).data.prop_getter.obj, + STACK_HEAD (ops, 1).data.prop_getter.prop, STACK_HEAD (IDX, 2)); + STACK_DROP (ops, 1); + STACK_DROP (U16, 1); + } + else + { + DUMP_OPCODE_3 (addition, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + } break; } case TOK_MINUS_EQ: { NEXT (assignment_expression); - DUMP_OPCODE_3 (substraction, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1)); + if (STACK_HEAD (U8, 1)) + { + STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); + DUMP_OPCODE_3 (substraction, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + DUMP_OPCODE_3 (prop_setter, STACK_HEAD (ops, 1).data.prop_getter.obj, + STACK_HEAD (ops, 1).data.prop_getter.prop, STACK_HEAD (IDX, 2)); + STACK_DROP (ops, 1); + STACK_DROP (U16, 1); + } + else + { + DUMP_OPCODE_3 (substraction, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + } break; } case TOK_LSHIFT_EQ: { NEXT (assignment_expression); - DUMP_OPCODE_3 (b_shift_left, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1)); + if (STACK_HEAD (U8, 1)) + { + STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); + DUMP_OPCODE_3 (b_shift_left, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + DUMP_OPCODE_3 (prop_setter, STACK_HEAD (ops, 1).data.prop_getter.obj, + STACK_HEAD (ops, 1).data.prop_getter.prop, STACK_HEAD (IDX, 2)); + STACK_DROP (ops, 1); + STACK_DROP (U16, 1); + } + else + { + DUMP_OPCODE_3 (b_shift_left, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + } break; } case TOK_RSHIFT_EQ: { NEXT (assignment_expression); - DUMP_OPCODE_3 (b_shift_right, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1)); + if (STACK_HEAD (U8, 1)) + { + STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); + DUMP_OPCODE_3 (b_shift_right, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + DUMP_OPCODE_3 (prop_setter, STACK_HEAD (ops, 1).data.prop_getter.obj, + STACK_HEAD (ops, 1).data.prop_getter.prop, STACK_HEAD (IDX, 2)); + STACK_DROP (ops, 1); + STACK_DROP (U16, 1); + } + else + { + DUMP_OPCODE_3 (b_shift_right, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + } break; } case TOK_RSHIFT_EX_EQ: { NEXT (assignment_expression); - DUMP_OPCODE_3 (b_shift_uright, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1)); + if (STACK_HEAD (U8, 1)) + { + STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); + DUMP_OPCODE_3 (b_shift_uright, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + DUMP_OPCODE_3 (prop_setter, STACK_HEAD (ops, 1).data.prop_getter.obj, + STACK_HEAD (ops, 1).data.prop_getter.prop, STACK_HEAD (IDX, 2)); + STACK_DROP (ops, 1); + STACK_DROP (U16, 1); + } + else + { + DUMP_OPCODE_3 (b_shift_uright, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + } break; } case TOK_AND_EQ: { NEXT (assignment_expression); - DUMP_OPCODE_3 (b_and, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1)); + if (STACK_HEAD (U8, 1)) + { + STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); + DUMP_OPCODE_3 (b_and, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + DUMP_OPCODE_3 (prop_setter, STACK_HEAD (ops, 1).data.prop_getter.obj, + STACK_HEAD (ops, 1).data.prop_getter.prop, STACK_HEAD (IDX, 2)); + STACK_DROP (ops, 1); + STACK_DROP (U16, 1); + } + else + { + DUMP_OPCODE_3 (b_and, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + } break; } case TOK_XOR_EQ: { NEXT (assignment_expression); - DUMP_OPCODE_3 (b_xor, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1)); + if (STACK_HEAD (U8, 1)) + { + STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); + DUMP_OPCODE_3 (b_xor, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + DUMP_OPCODE_3 (prop_setter, STACK_HEAD (ops, 1).data.prop_getter.obj, + STACK_HEAD (ops, 1).data.prop_getter.prop, STACK_HEAD (IDX, 2)); + STACK_DROP (ops, 1); + STACK_DROP (U16, 1); + } + else + { + DUMP_OPCODE_3 (b_xor, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + } break; } case TOK_OR_EQ: { NEXT (assignment_expression); - DUMP_OPCODE_3 (b_or, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 1)); + if (STACK_HEAD (U8, 1)) + { + STACK_PUSH (ops, deserialize_opcode (STACK_HEAD (U16, 0))); + DUMP_OPCODE_3 (b_or, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + DUMP_OPCODE_3 (prop_setter, STACK_HEAD (ops, 1).data.prop_getter.obj, + STACK_HEAD (ops, 1).data.prop_getter.prop, STACK_HEAD (IDX, 2)); + STACK_DROP (ops, 1); + STACK_DROP (U16, 1); + } + else + { + DUMP_OPCODE_3 (b_or, STACK_HEAD (IDX, 2), STACK_HEAD (IDX, 2), + STACK_HEAD (IDX, 1)); + } break; } default: @@ -1959,6 +2032,11 @@ parse_assignment_expression (void) STACK_DROP (IDX, 1); cleanup: + STACK_DROP (U8, 1); + + STACK_CHECK_USAGE (U16); + STACK_CHECK_USAGE (U8); + STACK_CHECK_USAGE (ops); STACK_CHECK_USAGE_LHS (); } diff --git a/src/liboptimizer/deserializer.c b/src/liboptimizer/deserializer.c index ea1f575ff..2293b9260 100644 --- a/src/liboptimizer/deserializer.c +++ b/src/liboptimizer/deserializer.c @@ -41,7 +41,15 @@ const void * deserialize_bytecode (void) { JERRY_ASSERT (STACK_SIZE (bytecode_opcodes) > 0); - return bytecode_opcodes.data; + return STACK_RAW_DATA (bytecode_opcodes); +} + +opcode_t +deserialize_opcode (opcode_counter_t oc) +{ + JERRY_ASSERT (STACK_SIZE (bytecode_opcodes) > 0); + JERRY_ASSERT (oc < STACK_SIZE (bytecode_opcodes)); + return STACK_ELEMENT (bytecode_opcodes, oc); } uint8_t diff --git a/src/liboptimizer/deserializer.h b/src/liboptimizer/deserializer.h index 45f067930..2ed304c5a 100644 --- a/src/liboptimizer/deserializer.h +++ b/src/liboptimizer/deserializer.h @@ -18,10 +18,12 @@ #include "globals.h" #include "ecma-globals.h" +#include "opcodes.h" const ecma_char_t *deserialize_string_by_id (uint8_t); ecma_number_t deserialize_num_by_id (uint8_t); const void *deserialize_bytecode (void); +opcode_t deserialize_opcode (opcode_counter_t); uint8_t deserialize_min_temp (void); #endif //DESERIALIZER_H diff --git a/src/liboptimizer/pretty-printer.c b/src/liboptimizer/pretty-printer.c index ce0a971af..52742f757 100644 --- a/src/liboptimizer/pretty-printer.c +++ b/src/liboptimizer/pretty-printer.c @@ -430,6 +430,7 @@ pp_opcode (opcode_counter_t oc, opcode_t opcode, bool is_rewrite) TODO (Refine to match new opcodes) CASE_VARG_0_LHS (obj_decl, lhs, "=", "{", "}") CASE_VARG_1_NAME_LHS (prop_getter, lhs, "=", "", obj, "[", prop, "]") + CASE_VARG_1_NAME_LHS (prop_setter, obj, "", "[", prop, " ] = ", rhs, "") CASE_THIS (this, lhs, "=", "this") CASE_DOUBLE_ADDRESS (delete_var, lhs, "=", "delete", name) CASE_TRIPLE_ADDRESS (delete_prop, lhs, "= delete", base, ".", name) diff --git a/src/liboptimizer/serializer.c b/src/liboptimizer/serializer.c index f2ceeda6f..412ac5387 100644 --- a/src/liboptimizer/serializer.c +++ b/src/liboptimizer/serializer.c @@ -50,6 +50,13 @@ serializer_dump_opcode (opcode_t opcode) STACK_PUSH (bytecode_opcodes, opcode); } +void +serializer_set_writing_position (opcode_counter_t oc) +{ + JERRY_ASSERT (oc < STACK_SIZE (bytecode_opcodes)); + STACK_DROP (bytecode_opcodes, STACK_SIZE (bytecode_opcodes) - oc); +} + void serializer_rewrite_opcode (const opcode_counter_t loc, opcode_t opcode) { diff --git a/src/liboptimizer/serializer.h b/src/liboptimizer/serializer.h index eff7bfc11..9fdf6b30f 100644 --- a/src/liboptimizer/serializer.h +++ b/src/liboptimizer/serializer.h @@ -22,18 +22,13 @@ #include "lp-string.h" void serializer_init (bool show_opcodes); - void serializer_dump_strings_and_nums (const lp_string *, uint8_t, const ecma_number_t *, uint8_t); - void serializer_dump_opcode (opcode_t); - +void serializer_set_writing_position (opcode_counter_t); void serializer_rewrite_opcode (const opcode_counter_t, opcode_t); - void serializer_print_opcodes (void); - void serializer_adjust_strings (void); - void serializer_free (void); #endif // SERIALIZER_H diff --git a/tests/jerry/object_literal.js b/tests/jerry/object_literal.js index 5995338c0..9ead044cd 100644 --- a/tests/jerry/object_literal.js +++ b/tests/jerry/object_literal.js @@ -28,19 +28,18 @@ assert (person["age"] === 50); assert (person.eyeColor === "blue"); assert (person["eyeColor"] === "blue"); -// FIXME Uncomment when prop_set generation will be ready -// var x = person; -// x.age = 40; -// assert (x.age === 40); -// assert (person.age === 40); +var x = person; +x.age = 40; +assert (x.age === 40); +assert (person.age === 40); -// var john = new Object(); -// john.firstName = "John"; -// john.lastName = "Doe"; -// john.age = 40; -// john.eyeColor = "blue"; +var john = new Object(); +john.firstName = "John"; +john.lastName = "Doe"; +john.age = 40; +john.eyeColor = "blue"; -// assert (person.firstName === john.firstName); -// assert (person.lastName === john.lastName); -// assert (person.age === john.age); -// assert (person.eyeColor === john.eyeColor); +assert (person.firstName === john.firstName); +assert (person.lastName === john.lastName); +assert (person.age === john.age); +assert (person.eyeColor === john.eyeColor);