blob: 630d3a774e4f6144e37c6cd19bf446ced3410b98 [file] [log] [blame]
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000043#include "date.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000045#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000046#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000048#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000049#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000050#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000051#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000052#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000053#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000054#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000055#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000057#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000058#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000059#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000060#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000061#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062
kasperl@chromium.org71affb52009-05-26 05:44:31 +000063namespace v8 {
64namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065
66
ager@chromium.org3e875802009-06-29 08:26:34 +000067#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000068 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000069
70// Cast the given object to a value of the specified type and store
71// it in a variable with the given name. If the object is not of the
72// expected type call IllegalOperation and return.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073#define CONVERT_ARG_CHECKED(Type, name, index) \
74 RUNTIME_ASSERT(args[index]->Is##Type()); \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000075 Type* name = Type::cast(args[index]);
76
77#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \
78 RUNTIME_ASSERT(args[index]->Is##Type()); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000079 Handle<Type> name = args.at<Type>(index);
80
kasper.lundbd3ec4e2008-07-09 11:06:54 +000081// Cast the given object to a boolean and store it in a variable with
82// the given name. If the object is not a boolean call IllegalOperation
83// and return.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000084#define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \
85 RUNTIME_ASSERT(args[index]->IsBoolean()); \
86 bool name = args[index]->IsTrue();
kasper.lundbd3ec4e2008-07-09 11:06:54 +000087
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000088// Cast the given argument to a Smi and store its value in an int variable
89// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000090// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000091#define CONVERT_SMI_ARG_CHECKED(name, index) \
92 RUNTIME_ASSERT(args[index]->IsSmi()); \
93 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000094
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000095// Cast the given argument to a double and store it in a variable with
96// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000098#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
99 RUNTIME_ASSERT(args[index]->IsNumber()); \
100 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000101
102// Call the specified converter on the object *comand store the result in
103// a variable of the specified type with the given name. If the
104// object is not a Number call IllegalOperation and return.
105#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
106 RUNTIME_ASSERT(obj->IsNumber()); \
107 type name = NumberTo##Type(obj);
108
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000109
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000110// Cast the given argument to PropertyDetails and store its value in a
111// variable with the given name. If the argument is not a Smi call
112// IllegalOperation and return.
113#define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \
114 RUNTIME_ASSERT(args[index]->IsSmi()); \
115 PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
116
117
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000118// Assert that the given argument has a valid value for a StrictModeFlag
119// and store it in a StrictModeFlag variable with the given name.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000120#define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \
121 RUNTIME_ASSERT(args[index]->IsSmi()); \
122 RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \
123 args.smi_at(index) == kNonStrictMode); \
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000124 StrictModeFlag name = \
125 static_cast<StrictModeFlag>(args.smi_at(index));
126
127
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000128// Assert that the given argument has a valid value for a LanguageMode
129// and store it in a LanguageMode variable with the given name.
130#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
131 ASSERT(args[index]->IsSmi()); \
132 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
133 args.smi_at(index) == STRICT_MODE || \
134 args.smi_at(index) == EXTENDED_MODE); \
135 LanguageMode name = \
136 static_cast<LanguageMode>(args.smi_at(index));
137
138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000139MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
140 JSObject* boilerplate) {
141 StackLimitCheck check(isolate);
142 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000143
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000144 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000145 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000146 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000147 if (!maybe_result->ToObject(&result)) return maybe_result;
148 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 JSObject* copy = JSObject::cast(result);
150
151 // Deep copy local properties.
152 if (copy->HasFastProperties()) {
153 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 for (int i = 0; i < properties->length(); i++) {
155 Object* value = properties->get(i);
156 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000157 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000158 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 if (!maybe_result->ToObject(&result)) return maybe_result;
160 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000161 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000162 }
163 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000164 int nof = copy->map()->inobject_properties();
165 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000166 Object* value = copy->InObjectPropertyAt(i);
167 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000168 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000169 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000170 if (!maybe_result->ToObject(&result)) return maybe_result;
171 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000172 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000173 }
174 }
175 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000176 { MaybeObject* maybe_result =
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000177 heap->AllocateFixedArray(copy->NumberOfLocalProperties());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000178 if (!maybe_result->ToObject(&result)) return maybe_result;
179 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000180 FixedArray* names = FixedArray::cast(result);
181 copy->GetLocalPropertyNames(names, 0);
182 for (int i = 0; i < names->length(); i++) {
183 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000184 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000185 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000186 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000187 // Only deep copy fields from the object literal expression.
188 // In particular, don't try to copy the length attribute of
189 // an array.
190 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000191 Object* value =
192 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000193 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000194 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000195 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000196 if (!maybe_result->ToObject(&result)) return maybe_result;
197 }
198 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000199 // Creating object copy for literals. No strict mode needed.
200 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000201 if (!maybe_result->ToObject(&result)) return maybe_result;
202 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000203 }
204 }
205 }
206
207 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000208 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000209 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000210 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000211 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000212 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000213 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000214 if (elements->map() == heap->fixed_cow_array_map()) {
215 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000216#ifdef DEBUG
217 for (int i = 0; i < elements->length(); i++) {
218 ASSERT(!elements->get(i)->IsJSObject());
219 }
220#endif
221 } else {
222 for (int i = 0; i < elements->length(); i++) {
223 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000224 ASSERT(value->IsSmi() ||
225 value->IsTheHole() ||
226 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000227 if (value->IsJSObject()) {
228 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000229 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
230 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000231 if (!maybe_result->ToObject(&result)) return maybe_result;
232 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000233 elements->set(i, result);
234 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000235 }
236 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000237 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000238 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000239 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000240 SeededNumberDictionary* element_dictionary = copy->element_dictionary();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000241 int capacity = element_dictionary->Capacity();
242 for (int i = 0; i < capacity; i++) {
243 Object* k = element_dictionary->KeyAt(i);
244 if (element_dictionary->IsKey(k)) {
245 Object* value = element_dictionary->ValueAt(i);
246 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000247 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000248 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
249 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000250 if (!maybe_result->ToObject(&result)) return maybe_result;
251 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000252 element_dictionary->ValueAtPut(i, result);
253 }
254 }
255 }
256 break;
257 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000258 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000259 UNIMPLEMENTED();
260 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000261 case EXTERNAL_PIXEL_ELEMENTS:
262 case EXTERNAL_BYTE_ELEMENTS:
263 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
264 case EXTERNAL_SHORT_ELEMENTS:
265 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
266 case EXTERNAL_INT_ELEMENTS:
267 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
268 case EXTERNAL_FLOAT_ELEMENTS:
269 case EXTERNAL_DOUBLE_ELEMENTS:
270 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000271 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000272 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000273 }
274 return copy;
275}
276
277
ager@chromium.org236ad962008-09-25 09:45:57 +0000278static Handle<Map> ComputeObjectLiteralMap(
279 Handle<Context> context,
280 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000281 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000282 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000283 int properties_length = constant_properties->length();
284 int number_of_properties = properties_length / 2;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000285 // Check that there are only symbols and array indices among keys.
286 int number_of_symbol_keys = 0;
287 for (int p = 0; p != properties_length; p += 2) {
288 Object* key = constant_properties->get(p);
289 uint32_t element_index = 0;
290 if (key->IsSymbol()) {
291 number_of_symbol_keys++;
292 } else if (key->ToArrayIndex(&element_index)) {
293 // An index key does not require space in the property backing store.
294 number_of_properties--;
295 } else {
296 // Bail out as a non-symbol non-index key makes caching impossible.
297 // ASSERT to make sure that the if condition after the loop is false.
298 ASSERT(number_of_symbol_keys != number_of_properties);
299 break;
ager@chromium.org236ad962008-09-25 09:45:57 +0000300 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000301 }
302 // If we only have symbols and array indices among keys then we can
303 // use the map cache in the global context.
304 const int kMaxKeys = 10;
305 if ((number_of_symbol_keys == number_of_properties) &&
306 (number_of_symbol_keys < kMaxKeys)) {
307 // Create the fixed array with the key.
308 Handle<FixedArray> keys =
309 isolate->factory()->NewFixedArray(number_of_symbol_keys);
310 if (number_of_symbol_keys > 0) {
311 int index = 0;
312 for (int p = 0; p < properties_length; p += 2) {
313 Object* key = constant_properties->get(p);
314 if (key->IsSymbol()) {
315 keys->set(index++, key);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000316 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000317 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000318 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000319 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000320 *is_result_from_cache = true;
321 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000322 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000323 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000325 Handle<Map>(context->object_function()->initial_map()),
326 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000327}
328
329
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000330static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000331 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000332 Handle<FixedArray> literals,
333 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000334
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000335
336static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000337 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000338 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000339 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000340 bool should_have_fast_elements,
341 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000342 // Get the global context from the literals array. This is the
343 // context in which the function was created and we use the object
344 // function from this context to create the object literal. We do
345 // not use the object function from the current global context
346 // because this might be the object function from another context
347 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000348 Handle<Context> context =
349 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000351 // In case we have function literals, we want the object to be in
352 // slow properties mode for now. We don't go in the map cache because
353 // maps with constant functions can't be shared if the functions are
354 // not the same (which is the common case).
355 bool is_result_from_cache = false;
356 Handle<Map> map = has_function_literal
357 ? Handle<Map>(context->object_function()->initial_map())
358 : ComputeObjectLiteralMap(context,
359 constant_properties,
360 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000362 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000363
364 // Normalize the elements of the boilerplate to save space if needed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000365 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000366
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000367 // Add the constant properties to the boilerplate.
368 int length = constant_properties->length();
369 bool should_transform =
370 !is_result_from_cache && boilerplate->HasFastProperties();
371 if (should_transform || has_function_literal) {
372 // Normalize the properties of object to avoid n^2 behavior
373 // when extending the object multiple properties. Indicate the number of
374 // properties to be added.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000375 JSObject::NormalizeProperties(
376 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000377 }
378
379 for (int index = 0; index < length; index +=2) {
380 Handle<Object> key(constant_properties->get(index+0), isolate);
381 Handle<Object> value(constant_properties->get(index+1), isolate);
382 if (value->IsFixedArray()) {
383 // The value contains the constant_properties of a
384 // simple object or array literal.
385 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
386 value = CreateLiteralBoilerplate(isolate, literals, array);
387 if (value.is_null()) return value;
388 }
389 Handle<Object> result;
390 uint32_t element_index = 0;
391 if (key->IsSymbol()) {
392 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
393 // Array index as string (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000394 result = JSObject::SetOwnElement(
395 boilerplate, element_index, value, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000396 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000397 Handle<String> name(String::cast(*key));
398 ASSERT(!name->AsArrayIndex(&element_index));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000399 result = JSObject::SetLocalPropertyIgnoreAttributes(
400 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000401 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000402 } else if (key->ToArrayIndex(&element_index)) {
403 // Array index (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000404 result = JSObject::SetOwnElement(
405 boilerplate, element_index, value, kNonStrictMode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000406 } else {
407 // Non-uint32 number.
408 ASSERT(key->IsNumber());
409 double num = key->Number();
410 char arr[100];
411 Vector<char> buffer(arr, ARRAY_SIZE(arr));
412 const char* str = DoubleToCString(num, buffer);
413 Handle<String> name =
414 isolate->factory()->NewStringFromAscii(CStrVector(str));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000415 result = JSObject::SetLocalPropertyIgnoreAttributes(
416 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000417 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 // If setting the property on the boilerplate throws an
419 // exception, the exception is converted to an empty handle in
420 // the handle based operations. In that case, we need to
421 // convert back to an exception.
422 if (result.is_null()) return result;
423 }
424
425 // Transform to fast properties if necessary. For object literals with
426 // containing function literals we defer this operation until after all
427 // computed properties have been assigned so that we can generate
428 // constant function properties.
429 if (should_transform && !has_function_literal) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000430 JSObject::TransformToFastProperties(
431 boilerplate, boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000432 }
433
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000434 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000435}
436
437
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000438MaybeObject* TransitionElements(Handle<Object> object,
439 ElementsKind to_kind,
440 Isolate* isolate) {
441 HandleScope scope(isolate);
442 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
443 ElementsKind from_kind =
444 Handle<JSObject>::cast(object)->map()->elements_kind();
445 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
446 Handle<Object> result = JSObject::TransitionElementsKind(
447 Handle<JSObject>::cast(object), to_kind);
448 if (result.is_null()) return isolate->ThrowIllegalOperation();
449 return *result;
450 }
451 return isolate->ThrowIllegalOperation();
452}
453
454
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000455static const int kSmiOnlyLiteralMinimumLength = 1024;
456
457
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000458Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000459 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000460 Handle<FixedArray> literals,
461 Handle<FixedArray> elements) {
462 // Create the JSArray.
463 Handle<JSFunction> constructor(
464 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000465 Handle<JSArray> object =
466 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000468 ElementsKind constant_elements_kind =
469 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
470 Handle<FixedArrayBase> constant_elements_values(
471 FixedArrayBase::cast(elements->get(1)));
472
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000473 Context* global_context = isolate->context()->global_context();
474 if (constant_elements_kind == FAST_SMI_ONLY_ELEMENTS) {
475 object->set_map(Map::cast(global_context->smi_js_array_map()));
476 } else if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
477 object->set_map(Map::cast(global_context->double_js_array_map()));
478 } else {
479 object->set_map(Map::cast(global_context->object_js_array_map()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000480 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000481
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000482 Handle<FixedArrayBase> copied_elements_values;
483 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
484 ASSERT(FLAG_smi_only_arrays);
485 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
486 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000487 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000488 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
489 constant_elements_kind == FAST_ELEMENTS);
490 const bool is_cow =
491 (constant_elements_values->map() ==
492 isolate->heap()->fixed_cow_array_map());
493 if (is_cow) {
494 copied_elements_values = constant_elements_values;
495#if DEBUG
496 Handle<FixedArray> fixed_array_values =
497 Handle<FixedArray>::cast(copied_elements_values);
498 for (int i = 0; i < fixed_array_values->length(); i++) {
499 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
500 }
501#endif
502 } else {
503 Handle<FixedArray> fixed_array_values =
504 Handle<FixedArray>::cast(constant_elements_values);
505 Handle<FixedArray> fixed_array_values_copy =
506 isolate->factory()->CopyFixedArray(fixed_array_values);
507 copied_elements_values = fixed_array_values_copy;
508 for (int i = 0; i < fixed_array_values->length(); i++) {
509 Object* current = fixed_array_values->get(i);
510 if (current->IsFixedArray()) {
511 // The value contains the constant_properties of a
512 // simple object or array literal.
513 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
514 Handle<Object> result =
515 CreateLiteralBoilerplate(isolate, literals, fa);
516 if (result.is_null()) return result;
517 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000518 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000519 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000520 }
521 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000522 object->set_elements(*copied_elements_values);
523 object->set_length(Smi::FromInt(copied_elements_values->length()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000524
525 // Ensure that the boilerplate object has FAST_ELEMENTS, unless the flag is
526 // on or the object is larger than the threshold.
527 if (!FLAG_smi_only_arrays &&
528 constant_elements_values->length() < kSmiOnlyLiteralMinimumLength) {
529 if (object->GetElementsKind() != FAST_ELEMENTS) {
530 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
531 }
532 }
533
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000534 return object;
535}
536
537
538static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000540 Handle<FixedArray> literals,
541 Handle<FixedArray> array) {
542 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000543 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000544 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000545 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 return CreateObjectLiteralBoilerplate(isolate,
547 literals,
548 elements,
549 true,
550 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000551 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000552 return CreateObjectLiteralBoilerplate(isolate,
553 literals,
554 elements,
555 false,
556 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000557 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000558 return Runtime::CreateArrayLiteralBoilerplate(
559 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000560 default:
561 UNREACHABLE();
562 return Handle<Object>::null();
563 }
564}
565
566
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000567RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000568 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000569 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000570 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000571 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000572 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000573 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000574 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
575 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000576
577 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000578 Handle<Object> boilerplate(literals->get(literals_index), isolate);
579 if (*boilerplate == isolate->heap()->undefined_value()) {
580 boilerplate = CreateObjectLiteralBoilerplate(isolate,
581 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000582 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 should_have_fast_elements,
584 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000585 if (boilerplate.is_null()) return Failure::Exception();
586 // Update the functions literal and return the boilerplate.
587 literals->set(literals_index, *boilerplate);
588 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000589 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000590}
591
592
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000593RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000594 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000595 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000596 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000597 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000598 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000599 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
601 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000602
603 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000604 Handle<Object> boilerplate(literals->get(literals_index), isolate);
605 if (*boilerplate == isolate->heap()->undefined_value()) {
606 boilerplate = CreateObjectLiteralBoilerplate(isolate,
607 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000608 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000609 should_have_fast_elements,
610 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000611 if (boilerplate.is_null()) return Failure::Exception();
612 // Update the functions literal and return the boilerplate.
613 literals->set(literals_index, *boilerplate);
614 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000615 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000616}
617
618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000619RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000620 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000621 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000622 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000623 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000624 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000625
626 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000627 Handle<Object> boilerplate(literals->get(literals_index), isolate);
628 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000629 boilerplate =
630 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000631 if (boilerplate.is_null()) return Failure::Exception();
632 // Update the functions literal and return the boilerplate.
633 literals->set(literals_index, *boilerplate);
634 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000635 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000636}
637
638
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000639RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000640 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000641 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000642 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000643 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000644 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000645
646 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 Handle<Object> boilerplate(literals->get(literals_index), isolate);
648 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000649 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000650 boilerplate =
651 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000652 if (boilerplate.is_null()) return Failure::Exception();
653 // Update the functions literal and return the boilerplate.
654 literals->set(literals_index, *boilerplate);
655 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000656 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000657 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000658 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000659 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000660 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000661}
662
663
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000664RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
665 ASSERT(args.length() == 2);
666 Object* handler = args[0];
667 Object* prototype = args[1];
668 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000669 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000670 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
671}
672
673
lrn@chromium.org34e60782011-09-15 07:25:40 +0000674RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
675 ASSERT(args.length() == 4);
676 Object* handler = args[0];
677 Object* call_trap = args[1];
678 Object* construct_trap = args[2];
679 Object* prototype = args[3];
680 Object* used_prototype =
681 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
682 return isolate->heap()->AllocateJSFunctionProxy(
683 handler, call_trap, construct_trap, used_prototype);
684}
685
686
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000687RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
688 ASSERT(args.length() == 1);
689 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000690 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000691}
692
693
lrn@chromium.org34e60782011-09-15 07:25:40 +0000694RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
695 ASSERT(args.length() == 1);
696 Object* obj = args[0];
697 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
698}
699
700
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000701RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
702 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000703 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000704 return proxy->handler();
705}
706
707
lrn@chromium.org34e60782011-09-15 07:25:40 +0000708RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
709 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000710 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000711 return proxy->call_trap();
712}
713
714
715RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
716 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000717 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000718 return proxy->construct_trap();
719}
720
721
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000722RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
723 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000724 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000725 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000726 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000727}
728
729
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000730RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
731 HandleScope scope(isolate);
732 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000733 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000734 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
735 holder->set_table(*table);
736 return *holder;
737}
738
739
740RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
741 HandleScope scope(isolate);
742 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000743 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000744 Handle<Object> key(args[1]);
745 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
746 table = ObjectHashSetAdd(table, key);
747 holder->set_table(*table);
748 return isolate->heap()->undefined_symbol();
749}
750
751
752RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
753 HandleScope scope(isolate);
754 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000755 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000756 Handle<Object> key(args[1]);
757 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
758 return isolate->heap()->ToBoolean(table->Contains(*key));
759}
760
761
762RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
763 HandleScope scope(isolate);
764 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000765 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000766 Handle<Object> key(args[1]);
767 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
768 table = ObjectHashSetRemove(table, key);
769 holder->set_table(*table);
770 return isolate->heap()->undefined_symbol();
771}
772
773
774RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
775 HandleScope scope(isolate);
776 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000777 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000778 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
779 holder->set_table(*table);
780 return *holder;
781}
782
783
784RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
785 HandleScope scope(isolate);
786 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000787 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000788 Handle<Object> key(args[1]);
789 return ObjectHashTable::cast(holder->table())->Lookup(*key);
790}
791
792
793RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
794 HandleScope scope(isolate);
795 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000796 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000797 Handle<Object> key(args[1]);
798 Handle<Object> value(args[2]);
799 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
800 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
801 holder->set_table(*new_table);
802 return *value;
803}
804
805
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000806RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
807 HandleScope scope(isolate);
808 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000809 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000810 ASSERT(weakmap->map()->inobject_properties() == 0);
811 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
812 weakmap->set_table(*table);
813 weakmap->set_next(Smi::FromInt(0));
814 return *weakmap;
815}
816
817
818RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
819 NoHandleAllocation ha;
820 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000821 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
822 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000823 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000824}
825
826
827RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
828 HandleScope scope(isolate);
829 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000830 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
831 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000832 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000833 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000834 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
835 weakmap->set_table(*new_table);
836 return *value;
837}
838
839
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000840RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000841 NoHandleAllocation ha;
842 ASSERT(args.length() == 1);
843 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000844 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000845 return JSObject::cast(obj)->class_name();
846}
847
ager@chromium.org7c537e22008-10-16 08:43:32 +0000848
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000849RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
850 NoHandleAllocation ha;
851 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000852 CONVERT_ARG_CHECKED(JSReceiver, input_obj, 0);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000853 Object* obj = input_obj;
854 // We don't expect access checks to be needed on JSProxy objects.
855 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000856 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000857 if (obj->IsAccessCheckNeeded() &&
858 !isolate->MayNamedAccess(JSObject::cast(obj),
859 isolate->heap()->Proto_symbol(),
860 v8::ACCESS_GET)) {
861 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
862 return isolate->heap()->undefined_value();
863 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000864 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000865 } while (obj->IsJSObject() &&
866 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000867 return obj;
868}
869
870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000871RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000872 NoHandleAllocation ha;
873 ASSERT(args.length() == 2);
874 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
875 Object* O = args[0];
876 Object* V = args[1];
877 while (true) {
878 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000879 if (prototype->IsNull()) return isolate->heap()->false_value();
880 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000881 V = prototype;
882 }
883}
884
885
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000886// Recursively traverses hidden prototypes if property is not found
887static void GetOwnPropertyImplementation(JSObject* obj,
888 String* name,
889 LookupResult* result) {
890 obj->LocalLookupRealNamedProperty(name, result);
891
892 if (!result->IsProperty()) {
893 Object* proto = obj->GetPrototype();
894 if (proto->IsJSObject() &&
895 JSObject::cast(proto)->map()->is_hidden_prototype())
896 GetOwnPropertyImplementation(JSObject::cast(proto),
897 name, result);
898 }
899}
900
901
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000902static bool CheckAccessException(LookupResult* result,
903 v8::AccessType access_type) {
904 if (result->type() == CALLBACKS) {
905 Object* callback = result->GetCallbackObject();
906 if (callback->IsAccessorInfo()) {
907 AccessorInfo* info = AccessorInfo::cast(callback);
908 bool can_access =
909 (access_type == v8::ACCESS_HAS &&
910 (info->all_can_read() || info->all_can_write())) ||
911 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
912 (access_type == v8::ACCESS_SET && info->all_can_write());
913 return can_access;
914 }
915 }
916
917 return false;
918}
919
920
921static bool CheckAccess(JSObject* obj,
922 String* name,
923 LookupResult* result,
924 v8::AccessType access_type) {
925 ASSERT(result->IsProperty());
926
927 JSObject* holder = result->holder();
928 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000929 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000930 while (true) {
931 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000932 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000933 // Access check callback denied the access, but some properties
934 // can have a special permissions which override callbacks descision
935 // (currently see v8::AccessControl).
936 break;
937 }
938
939 if (current == holder) {
940 return true;
941 }
942
943 current = JSObject::cast(current->GetPrototype());
944 }
945
946 // API callbacks can have per callback access exceptions.
947 switch (result->type()) {
948 case CALLBACKS: {
949 if (CheckAccessException(result, access_type)) {
950 return true;
951 }
952 break;
953 }
954 case INTERCEPTOR: {
955 // If the object has an interceptor, try real named properties.
956 // Overwrite the result to fetch the correct property later.
957 holder->LookupRealNamedProperty(name, result);
958 if (result->IsProperty()) {
959 if (CheckAccessException(result, access_type)) {
960 return true;
961 }
962 }
963 break;
964 }
965 default:
966 break;
967 }
968
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000969 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000970 return false;
971}
972
973
974// TODO(1095): we should traverse hidden prototype hierachy as well.
975static bool CheckElementAccess(JSObject* obj,
976 uint32_t index,
977 v8::AccessType access_type) {
978 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000979 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000980 return false;
981 }
982
983 return true;
984}
985
986
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000987// Enumerator used as indices into the array returned from GetOwnProperty
988enum PropertyDescriptorIndices {
989 IS_ACCESSOR_INDEX,
990 VALUE_INDEX,
991 GETTER_INDEX,
992 SETTER_INDEX,
993 WRITABLE_INDEX,
994 ENUMERABLE_INDEX,
995 CONFIGURABLE_INDEX,
996 DESCRIPTOR_SIZE
997};
998
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000999
1000static MaybeObject* GetOwnProperty(Isolate* isolate,
1001 Handle<JSObject> obj,
1002 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001003 Heap* heap = isolate->heap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001004 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1005 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001006 LookupResult result(isolate);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001007 // This could be an element.
1008 uint32_t index;
1009 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001010 switch (obj->HasLocalElement(index)) {
1011 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001012 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001013
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001014 case JSObject::STRING_CHARACTER_ELEMENT: {
1015 // Special handling of string objects according to ECMAScript 5
1016 // 15.5.5.2. Note that this might be a string object with elements
1017 // other than the actual string value. This is covered by the
1018 // subsequent cases.
1019 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1020 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001021 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001022
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001023 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001024 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001025 elms->set(WRITABLE_INDEX, heap->false_value());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001026 elms->set(ENUMERABLE_INDEX, heap->true_value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001027 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001028 return *desc;
1029 }
1030
1031 case JSObject::INTERCEPTED_ELEMENT:
1032 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001033 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001034 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001035 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001036 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001037 elms->set(WRITABLE_INDEX, heap->true_value());
1038 elms->set(ENUMERABLE_INDEX, heap->true_value());
1039 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001040 return *desc;
1041 }
1042
1043 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001044 Handle<JSObject> holder = obj;
1045 if (obj->IsJSGlobalProxy()) {
1046 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001047 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001048 ASSERT(proto->IsJSGlobalObject());
1049 holder = Handle<JSObject>(JSObject::cast(proto));
1050 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001051 FixedArray* elements = FixedArray::cast(holder->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001052 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001053 if (elements->map() == heap->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001054 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001055 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001056 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001057 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001058 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001059 ASSERT(entry != SeededNumberDictionary::kNotFound);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001060 PropertyDetails details = dictionary->DetailsAt(entry);
1061 switch (details.type()) {
1062 case CALLBACKS: {
1063 // This is an accessor property with getter and/or setter.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001064 AccessorPair* accessors =
1065 AccessorPair::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001066 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001067 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00001068 elms->set(GETTER_INDEX, accessors->GetComponent(ACCESSOR_GETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001069 }
1070 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00001071 elms->set(SETTER_INDEX, accessors->GetComponent(ACCESSOR_SETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001072 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001073 break;
1074 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001075 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001076 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001077 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001078 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001079 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001080 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001081 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001082 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001083 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001084 default:
1085 UNREACHABLE();
1086 break;
1087 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001088 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1089 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001090 return *desc;
1091 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001092 }
1093 }
1094
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001095 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001096 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001097
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001098 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001099 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001100 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001101
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001102 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001103 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001104 }
1105
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001106 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1107 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001108
1109 bool is_js_accessor = (result.type() == CALLBACKS) &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001110 (result.GetCallbackObject()->IsAccessorPair());
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001111
1112 if (is_js_accessor) {
1113 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001114 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001115
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001116 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001117 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00001118 elms->set(GETTER_INDEX, accessors->GetComponent(ACCESSOR_GETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001119 }
1120 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00001121 elms->set(SETTER_INDEX, accessors->GetComponent(ACCESSOR_SETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001122 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001123 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001124 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1125 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001126
1127 PropertyAttributes attrs;
1128 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001129 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001130 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1131 if (!maybe_value->ToObject(&value)) return maybe_value;
1132 }
1133 elms->set(VALUE_INDEX, value);
1134 }
1135
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001136 return *desc;
1137}
1138
1139
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001140// Returns an array with the property description:
1141// if args[1] is not a property on args[0]
1142// returns undefined
1143// if args[1] is a data property on args[0]
1144// [false, value, Writeable, Enumerable, Configurable]
1145// if args[1] is an accessor on args[0]
1146// [true, GetFunction, SetFunction, Enumerable, Configurable]
1147RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
1148 ASSERT(args.length() == 2);
1149 HandleScope scope(isolate);
1150 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1151 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
1152 return GetOwnProperty(isolate, obj, name);
1153}
1154
1155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001156RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001157 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001158 CONVERT_ARG_CHECKED(JSObject, obj, 0);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001159 return obj->PreventExtensions();
1160}
1161
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001163RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001164 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001165 CONVERT_ARG_CHECKED(JSObject, obj, 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001166 if (obj->IsJSGlobalProxy()) {
1167 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001168 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001169 ASSERT(proto->IsJSGlobalObject());
1170 obj = JSObject::cast(proto);
1171 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001172 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001173}
1174
1175
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001176RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001177 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001178 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001179 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0);
1180 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
1181 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001182 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1183 if (result.is_null()) return Failure::Exception();
1184 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185}
1186
1187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001188RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001189 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001190 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001191 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001192 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193}
1194
1195
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001196RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001197 ASSERT(args.length() == 1);
1198 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001199 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001200 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001201}
1202
1203
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001204RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001206 CONVERT_ARG_CHECKED(HeapObject, templ, 0);
1207 CONVERT_SMI_ARG_CHECKED(index, 1)
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001208 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1209 InstanceType type = templ->map()->instance_type();
1210 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1211 type == OBJECT_TEMPLATE_INFO_TYPE);
1212 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001213 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001214 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1215 } else {
1216 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1217 }
1218 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219}
1220
1221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001222RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001223 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001224 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001225 Map* old_map = object->map();
1226 bool needs_access_checks = old_map->is_access_check_needed();
1227 if (needs_access_checks) {
1228 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001229 Object* new_map;
1230 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1231 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1232 }
ager@chromium.org32912102009-01-16 10:38:43 +00001233
1234 Map::cast(new_map)->set_is_access_check_needed(false);
1235 object->set_map(Map::cast(new_map));
1236 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001237 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001238}
1239
1240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001241RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001242 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001243 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001244 Map* old_map = object->map();
1245 if (!old_map->is_access_check_needed()) {
1246 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001247 Object* new_map;
1248 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1249 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1250 }
ager@chromium.org32912102009-01-16 10:38:43 +00001251
1252 Map::cast(new_map)->set_is_access_check_needed(true);
1253 object->set_map(Map::cast(new_map));
1254 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001255 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001256}
1257
1258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001259static Failure* ThrowRedeclarationError(Isolate* isolate,
1260 const char* type,
1261 Handle<String> name) {
1262 HandleScope scope(isolate);
1263 Handle<Object> type_handle =
1264 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265 Handle<Object> args[2] = { type_handle, name };
1266 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001267 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1268 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269}
1270
1271
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001272RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001273 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001274 HandleScope scope(isolate);
1275 Handle<GlobalObject> global = Handle<GlobalObject>(
1276 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277
ager@chromium.org3811b432009-10-28 14:53:37 +00001278 Handle<Context> context = args.at<Context>(0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001279 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001280 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282 // Traverse the name/value pairs and set the properties.
1283 int length = pairs->length();
1284 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001285 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001287 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001288
1289 // We have to declare a global const property. To capture we only
1290 // assign to it when evaluating the assignment for "const x =
1291 // <expr>" the initial value is the hole.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001292 bool is_var = value->IsUndefined();
1293 bool is_const = value->IsTheHole();
1294 bool is_function = value->IsSharedFunctionInfo();
1295 bool is_module = value->IsJSModule();
1296 ASSERT(is_var + is_const + is_function + is_module == 1);
1297
1298 if (is_var || is_const) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001299 // Lookup the property in the global object, and don't set the
1300 // value of the variable if the property is already there.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001301 // Do the lookup locally only, see ES5 errata.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001302 LookupResult lookup(isolate);
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00001303 if (FLAG_es52_globals)
1304 global->LocalLookup(*name, &lookup);
1305 else
1306 global->Lookup(*name, &lookup);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001307 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001308 // We found an existing property. Unless it was an interceptor
1309 // that claims the property is absent, skip this declaration.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001310 if (lookup.type() != INTERCEPTOR) continue;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001311 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001312 if (attributes != ABSENT) continue;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001313 // Fall-through and introduce the absent property by using
1314 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001316 } else if (is_function) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001317 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001318 Handle<SharedFunctionInfo> shared =
1319 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001320 Handle<JSFunction> function =
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001321 isolate->factory()->NewFunctionFromSharedFunctionInfo(
1322 shared, context, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001323 value = function;
1324 }
1325
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001326 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001327 global->LocalLookup(*name, &lookup);
1328
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001329 // Compute the property attributes. According to ECMA-262,
1330 // the property must be non-configurable except in eval.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001331 int attr = NONE;
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001332 bool is_eval = DeclareGlobalsEvalFlag::decode(flags);
1333 if (!is_eval || is_module) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001334 attr |= DONT_DELETE;
1335 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001336 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001337 if (is_const || is_module || (is_native && is_function)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001338 attr |= READ_ONLY;
1339 }
1340
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001341 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1342
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001343 if (!lookup.IsProperty() || is_function || is_module) {
1344 // If the local property exists, check that we can reconfigure it
1345 // as required for function declarations.
1346 if (lookup.IsProperty() && lookup.IsDontDelete()) {
1347 if (lookup.IsReadOnly() || lookup.IsDontEnum() ||
1348 lookup.type() == CALLBACKS) {
1349 return ThrowRedeclarationError(
1350 isolate, is_function ? "function" : "module", name);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001351 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001352 // If the existing property is not configurable, keep its attributes.
1353 attr = lookup.GetAttributes();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001354 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001355 // Define or redefine own property.
1356 RETURN_IF_EMPTY_HANDLE(isolate,
1357 JSObject::SetLocalPropertyIgnoreAttributes(
1358 global, name, value, static_cast<PropertyAttributes>(attr)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001359 } else {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001360 // Do a [[Put]] on the existing (own) property.
1361 RETURN_IF_EMPTY_HANDLE(isolate,
1362 JSObject::SetProperty(
1363 global, name, value, static_cast<PropertyAttributes>(attr),
1364 language_mode == CLASSIC_MODE ? kNonStrictMode : kStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001365 }
1366 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001367
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001368 ASSERT(!isolate->has_pending_exception());
1369 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001370}
1371
1372
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001373RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001374 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001375 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001377 // Declarations are always made in a function or global context. In the
1378 // case of eval code, the context passed is the context of the caller,
1379 // which may be some nested context and not the declaration context.
1380 RUNTIME_ASSERT(args[0]->IsContext());
1381 Handle<Context> context(Context::cast(args[0])->declaration_context());
1382
ager@chromium.org7c537e22008-10-16 08:43:32 +00001383 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001384 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001385 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001386 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001387
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001388 int index;
1389 PropertyAttributes attributes;
1390 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001391 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001392 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001393 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001394
1395 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001396 // The name was declared before; check for conflicting re-declarations.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001397 // Note: this is actually inconsistent with what happens for globals (where
1398 // we silently ignore such declarations).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1400 // Functions are not read-only.
1401 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1402 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001403 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001404 }
1405
1406 // Initialize it if necessary.
1407 if (*initial_value != NULL) {
1408 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001409 ASSERT(holder.is_identical_to(context));
1410 if (((attributes & READ_ONLY) == 0) ||
1411 context->get(index)->IsTheHole()) {
1412 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413 }
1414 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001415 // Slow case: The property is in the context extension object of a
1416 // function context or the global object of a global context.
1417 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001418 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001419 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001420 JSReceiver::SetProperty(object, name, initial_value, mode,
1421 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422 }
1423 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001424
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001425 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001426 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001427 // "declared" in the function context's extension context or as a
1428 // property of the the global object.
1429 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001430 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001431 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001432 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001433 // Context extension objects are allocated lazily.
1434 ASSERT(context->IsFunctionContext());
1435 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001436 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001437 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001438 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001439 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001440
ager@chromium.org7c537e22008-10-16 08:43:32 +00001441 // Declare the property by setting it to the initial value if provided,
1442 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1443 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001444 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001445 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001446 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001447 // Declaring a const context slot is a conflicting declaration if
1448 // there is a callback with that name in a prototype. It is
1449 // allowed to introduce const variables in
1450 // JSContextExtensionObjects. They are treated specially in
1451 // SetProperty and no setters are invoked for those since they are
1452 // not real JSObjects.
1453 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001454 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001455 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001456 object->Lookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001457 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001458 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001459 }
1460 }
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001461 if (object->IsJSGlobalObject()) {
1462 // Define own property on the global object.
1463 RETURN_IF_EMPTY_HANDLE(isolate,
1464 JSObject::SetLocalPropertyIgnoreAttributes(object, name, value, mode));
1465 } else {
1466 RETURN_IF_EMPTY_HANDLE(isolate,
1467 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
1468 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001469 }
1470
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001471 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472}
1473
1474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001475RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001476 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001477 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001478 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001479 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001480
1481 // Determine if we need to assign to the variable if it already
1482 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001483 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1484 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001485
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001486 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001487 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001488 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001489 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1490 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1491 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001492
1493 // According to ECMA-262, section 12.2, page 62, the property must
1494 // not be deletable.
1495 PropertyAttributes attributes = DONT_DELETE;
1496
1497 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001498 // there, there is a property with this name in the prototype chain.
1499 // We follow Safari and Firefox behavior and only set the property
1500 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001501 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001502 // Note that objects can have hidden prototypes, so we need to traverse
1503 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001504 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001505 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001506 while (object->IsJSObject() &&
1507 JSObject::cast(object)->map()->is_hidden_prototype()) {
1508 JSObject* raw_holder = JSObject::cast(object);
1509 raw_holder->LocalLookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001510 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001511 HandleScope handle_scope(isolate);
1512 Handle<JSObject> holder(raw_holder);
1513 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1514 // Update the raw pointer in case it's changed due to GC.
1515 raw_holder = *holder;
1516 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1517 // Found an interceptor that's not read only.
1518 if (assign) {
1519 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001520 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001521 } else {
1522 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001523 }
1524 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001525 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001526 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001527 }
1528
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001529 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001530 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001531 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001532 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001533 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001534 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535}
1536
1537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001538RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001539 // All constants are declared with an initial value. The name
1540 // of the constant is the first argument and the initial value
1541 // is the second.
1542 RUNTIME_ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001543 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001544 Handle<Object> value = args.at<Object>(1);
1545
1546 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001547 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001548
1549 // According to ECMA-262, section 12.2, page 62, the property must
1550 // not be deletable. Since it's a const, it must be READ_ONLY too.
1551 PropertyAttributes attributes =
1552 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1553
1554 // Lookup the property locally in the global object. If it isn't
1555 // there, we add the property and take special precautions to always
1556 // add it as a local property even in case of callbacks in the
1557 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001558 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001559 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 global->LocalLookup(*name, &lookup);
1561 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001562 return global->SetLocalPropertyIgnoreAttributes(*name,
1563 *value,
1564 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001565 }
1566
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001567 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001569 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001570 HandleScope handle_scope(isolate);
1571 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001572
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001573 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001574 // property through an interceptor and only do it if it's
1575 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001576 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001577 RETURN_IF_EMPTY_HANDLE(
1578 isolate,
1579 JSReceiver::SetProperty(global, name, value, attributes,
1580 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001581 return *value;
1582 }
1583
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001584 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001585 // constant. For now, we determine this by checking if the
1586 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001587 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001588 PropertyType type = lookup.type();
1589 if (type == FIELD) {
1590 FixedArray* properties = global->properties();
1591 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001592 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001593 properties->set(index, *value);
1594 }
1595 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001596 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1597 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001598 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001599 }
1600 } else {
1601 // Ignore re-initialization of constants that have already been
1602 // assigned a function value.
1603 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1604 }
1605
1606 // Use the set value as the result of the operation.
1607 return *value;
1608}
1609
1610
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001611RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001612 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001613 ASSERT(args.length() == 3);
1614
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001615 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001616 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001617
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001618 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001619 RUNTIME_ASSERT(args[1]->IsContext());
1620 Handle<Context> context(Context::cast(args[1])->declaration_context());
1621
1622 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001623
1624 int index;
1625 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001626 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001627 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001628 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001629 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001630
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001631 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001632 ASSERT(holder->IsContext());
1633 // Property was found in a context. Perform the assignment if we
1634 // found some non-constant or an uninitialized constant.
1635 Handle<Context> context = Handle<Context>::cast(holder);
1636 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1637 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001638 }
1639 return *value;
1640 }
1641
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001642 // The property could not be found, we introduce it as a property of the
1643 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001644 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001645 Handle<JSObject> global = Handle<JSObject>(
1646 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001647 // Strict mode not needed (const disallowed in strict mode).
1648 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001649 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001650 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001651 return *value;
1652 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001653
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001654 // The property was present in some function's context extension object,
1655 // as a property on the subject of a with, or as a property of the global
1656 // object.
1657 //
1658 // In most situations, eval-introduced consts should still be present in
1659 // the context extension object. However, because declaration and
1660 // initialization are separate, the property might have been deleted
1661 // before we reach the initialization point.
1662 //
1663 // Example:
1664 //
1665 // function f() { eval("delete x; const x;"); }
1666 //
1667 // In that case, the initialization behaves like a normal assignment.
1668 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001669
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001670 if (*object == context->extension()) {
1671 // This is the property that was introduced by the const declaration.
1672 // Set it if it hasn't been set before. NOTE: We cannot use
1673 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001674 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001675 object->LocalLookupRealNamedProperty(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001676 ASSERT(lookup.IsFound()); // the property was declared
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001677 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1678
1679 PropertyType type = lookup.type();
1680 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001681 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001682 int index = lookup.GetFieldIndex();
1683 if (properties->get(index)->IsTheHole()) {
1684 properties->set(index, *value);
1685 }
1686 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001687 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1688 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001689 }
1690 } else {
1691 // We should not reach here. Any real, named property should be
1692 // either a field or a dictionary slot.
1693 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001694 }
1695 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001696 // The property was found on some other object. Set it if it is not a
1697 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001698 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001699 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001700 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001701 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001702 JSReceiver::SetProperty(object, name, value, attributes,
1703 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001704 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001705 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001706
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001707 return *value;
1708}
1709
1710
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001711RUNTIME_FUNCTION(MaybeObject*,
1712 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001713 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001714 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001715 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001716 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001717 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001718 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001719 }
1720 return *object;
1721}
1722
1723
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001724RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001725 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001726 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001727 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
1728 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001729 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001730 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001731 CONVERT_SMI_ARG_CHECKED(index, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001732 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001733 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001734 RUNTIME_ASSERT(index >= 0);
1735 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001736 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001737 Handle<Object> result = RegExpImpl::Exec(regexp,
1738 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001739 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001740 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001741 if (result.is_null()) return Failure::Exception();
1742 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001743}
1744
1745
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001746RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001747 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001748 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001749 if (elements_count < 0 ||
1750 elements_count > FixedArray::kMaxLength ||
1751 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001752 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001753 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001754 Object* new_object;
1755 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001756 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001757 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1758 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001759 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001760 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1761 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001762 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1763 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001764 {
1765 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001766 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001767 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001768 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001769 }
1770 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001771 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001772 array->set_elements(elements);
1773 array->set_length(Smi::FromInt(elements_count));
1774 // Write in-object properties after the length of the array.
1775 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1776 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1777 return array;
1778}
1779
1780
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001781RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001782 AssertNoAllocation no_alloc;
1783 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001784 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1785 CONVERT_ARG_CHECKED(String, source, 1);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001786
1787 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001788 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001789
1790 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001791 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001792
1793 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001794 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001795
1796 Map* map = regexp->map();
1797 Object* constructor = map->constructor();
1798 if (constructor->IsJSFunction() &&
1799 JSFunction::cast(constructor)->initial_map() == map) {
1800 // If we still have the original map, set in-object properties directly.
1801 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001802 // Both true and false are immovable immortal objects so no need for write
1803 // barrier.
1804 regexp->InObjectPropertyAtPut(
1805 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1806 regexp->InObjectPropertyAtPut(
1807 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1808 regexp->InObjectPropertyAtPut(
1809 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001810 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1811 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001812 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001813 return regexp;
1814 }
1815
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001816 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001817 PropertyAttributes final =
1818 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1819 PropertyAttributes writable =
1820 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001821 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001822 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001823 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001824 source,
1825 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001826 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001827 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001828 global,
1829 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001830 ASSERT(!result->IsFailure());
1831 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001832 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001833 ignoreCase,
1834 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001835 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001836 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001837 multiline,
1838 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001839 ASSERT(!result->IsFailure());
1840 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001841 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001842 Smi::FromInt(0),
1843 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001844 ASSERT(!result->IsFailure());
1845 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001846 return regexp;
1847}
1848
1849
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001850RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001851 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001852 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001853 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001854 // This is necessary to enable fast checks for absence of elements
1855 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001856 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001857 return Smi::FromInt(0);
1858}
1859
1860
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001861static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1862 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001863 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001864 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001865 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1866 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1867 Handle<JSFunction> optimized =
1868 isolate->factory()->NewFunction(key,
1869 JS_OBJECT_TYPE,
1870 JSObject::kHeaderSize,
1871 code,
1872 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001873 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001874 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001875 return optimized;
1876}
1877
1878
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001879RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001880 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001881 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001882 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001883
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001884 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1885 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1886 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1887 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1888 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1889 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1890 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001891
1892 return *holder;
1893}
1894
1895
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001896RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001897 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001898 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001899
1900 if (!callable->IsJSFunction()) {
1901 HandleScope scope(isolate);
1902 bool threw = false;
1903 Handle<Object> delegate =
1904 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
1905 if (threw) return Failure::Exception();
1906 callable = JSFunction::cast(*delegate);
1907 }
1908 JSFunction* function = JSFunction::cast(callable);
1909
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001910 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001911 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001912 return isolate->heap()->undefined_value();
1913 }
1914 // Returns undefined for strict or native functions, or
1915 // the associated global receiver for "normal" functions.
1916
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001917 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001918 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001919 return global_context->global()->global_receiver();
1920}
1921
1922
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001923RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001924 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001925 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001926 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001927 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001928 Handle<String> pattern = args.at<String>(2);
1929 Handle<String> flags = args.at<String>(3);
1930
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001931 // Get the RegExp function from the context in the literals array.
1932 // This is the RegExp function from the context in which the
1933 // function was created. We do not use the RegExp function from the
1934 // current global context because this might be the RegExp function
1935 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001936 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001937 Handle<JSFunction>(
1938 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001939 // Compute the regular expression literal.
1940 bool has_pending_exception;
1941 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001942 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1943 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001944 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001945 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001946 return Failure::Exception();
1947 }
1948 literals->set(index, *regexp);
1949 return *regexp;
1950}
1951
1952
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001953RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001954 NoHandleAllocation ha;
1955 ASSERT(args.length() == 1);
1956
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001957 CONVERT_ARG_CHECKED(JSFunction, f, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001958 return f->shared()->name();
1959}
1960
1961
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001962RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001963 NoHandleAllocation ha;
1964 ASSERT(args.length() == 2);
1965
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001966 CONVERT_ARG_CHECKED(JSFunction, f, 0);
1967 CONVERT_ARG_CHECKED(String, name, 1);
ager@chromium.org236ad962008-09-25 09:45:57 +00001968 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001969 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001970}
1971
1972
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001973RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1974 NoHandleAllocation ha;
1975 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001976 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001977 return isolate->heap()->ToBoolean(
1978 f->shared()->name_should_print_as_anonymous());
1979}
1980
1981
1982RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1983 NoHandleAllocation ha;
1984 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001985 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001986 f->shared()->set_name_should_print_as_anonymous(true);
1987 return isolate->heap()->undefined_value();
1988}
1989
1990
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001991RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001992 NoHandleAllocation ha;
1993 ASSERT(args.length() == 1);
1994
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001995 CONVERT_ARG_CHECKED(JSFunction, f, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001996 Object* obj = f->RemovePrototype();
1997 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001998
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001999 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002000}
2001
2002
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002003RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002004 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002005 ASSERT(args.length() == 1);
2006
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002007 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002008 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2009 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002010
2011 return *GetScriptWrapper(Handle<Script>::cast(script));
2012}
2013
2014
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002015RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002016 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002017 ASSERT(args.length() == 1);
2018
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002019 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002020 Handle<SharedFunctionInfo> shared(f->shared());
2021 return *shared->GetSourceCode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002022}
2023
2024
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002025RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002026 NoHandleAllocation ha;
2027 ASSERT(args.length() == 1);
2028
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002029 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002030 int pos = fun->shared()->start_position();
2031 return Smi::FromInt(pos);
2032}
2033
2034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002035RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002036 ASSERT(args.length() == 2);
2037
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002038 CONVERT_ARG_CHECKED(Code, code, 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002039 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2040
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002041 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2042
2043 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002044 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002045}
2046
2047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002048RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002049 NoHandleAllocation ha;
2050 ASSERT(args.length() == 2);
2051
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002052 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2053 CONVERT_ARG_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002054 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002055 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002056}
2057
2058
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002059RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002060 NoHandleAllocation ha;
2061 ASSERT(args.length() == 2);
2062
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002063 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2064 CONVERT_SMI_ARG_CHECKED(length, 1);
2065 fun->shared()->set_length(length);
2066 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002067}
2068
2069
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002070RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002071 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002072 ASSERT(args.length() == 2);
2073
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002074 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002075 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002076 Object* obj;
2077 { MaybeObject* maybe_obj =
2078 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2079 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2080 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002081 return args[0]; // return TOS
2082}
2083
2084
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002085RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2086 NoHandleAllocation ha;
2087 RUNTIME_ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002088 CONVERT_ARG_CHECKED(JSFunction, function, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002089
2090 MaybeObject* maybe_name =
2091 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2092 String* name;
2093 if (!maybe_name->To(&name)) return maybe_name;
2094
2095 if (function->HasFastProperties()) {
2096 // Construct a new field descriptor with updated attributes.
2097 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2098 int index = instance_desc->Search(name);
2099 ASSERT(index != DescriptorArray::kNotFound);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00002100 PropertyDetails details = instance_desc->GetDetails(index);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002101 CallbacksDescriptor new_desc(name,
2102 instance_desc->GetValue(index),
2103 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2104 details.index());
2105 // Construct a new field descriptors array containing the new descriptor.
2106 Object* descriptors_unchecked;
2107 { MaybeObject* maybe_descriptors_unchecked =
2108 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2109 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2110 return maybe_descriptors_unchecked;
2111 }
2112 }
2113 DescriptorArray* new_descriptors =
2114 DescriptorArray::cast(descriptors_unchecked);
2115 // Create a new map featuring the new field descriptors array.
2116 Object* map_unchecked;
2117 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2118 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2119 return maybe_map_unchecked;
2120 }
2121 }
2122 Map* new_map = Map::cast(map_unchecked);
2123 new_map->set_instance_descriptors(new_descriptors);
2124 function->set_map(new_map);
2125 } else { // Dictionary properties.
2126 // Directly manipulate the property details.
2127 int entry = function->property_dictionary()->FindEntry(name);
2128 ASSERT(entry != StringDictionary::kNotFound);
2129 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2130 PropertyDetails new_details(
2131 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2132 details.type(),
2133 details.index());
2134 function->property_dictionary()->DetailsAtPut(entry, new_details);
2135 }
2136 return function;
2137}
2138
2139
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002140RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002141 NoHandleAllocation ha;
2142 ASSERT(args.length() == 1);
2143
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002144 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002145 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002146}
2147
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002148
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002149RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002150 NoHandleAllocation ha;
2151 ASSERT(args.length() == 1);
2152
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002153 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002154 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002155}
2156
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002157
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002158RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002159 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002160 ASSERT(args.length() == 2);
2161
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002162 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002163 Handle<Object> code = args.at<Object>(1);
2164
2165 Handle<Context> context(target->context());
2166
2167 if (!code->IsNull()) {
2168 RUNTIME_ASSERT(code->IsJSFunction());
2169 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002170 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002171
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002172 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002173 return Failure::Exception();
2174 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002175 // Since we don't store the source for this we should never
2176 // optimize this.
2177 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002178 // Set the code, scope info, formal parameter count,
2179 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002180 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002181 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002182 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002183 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002184 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002185 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002186 // Set the source code of the target function to undefined.
2187 // SetCode is only used for built-in constructors like String,
2188 // Array, and Object, and some web code
2189 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002190 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002191 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002192 // Clear the optimization hints related to the compiled code as these are no
2193 // longer valid when the code is overwritten.
2194 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002195 context = Handle<Context>(fun->context());
2196
2197 // Make sure we get a fresh copy of the literal vector to avoid
2198 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002199 int number_of_literals = fun->NumberOfLiterals();
2200 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002201 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002202 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002203 // Insert the object, regexp and array functions in the literals
2204 // array prefix. These are the functions that will be used when
2205 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002206 literals->set(JSFunction::kLiteralGlobalContextIndex,
2207 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002208 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002209 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002210 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002211
2212 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2213 isolate->logger()->LogExistingFunction(
2214 shared, Handle<Code>(shared->code()));
2215 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002216 }
2217
2218 target->set_context(*context);
2219 return *target;
2220}
2221
2222
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002223RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002224 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002225 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002226 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002227 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002228 RUNTIME_ASSERT(num >= 0);
2229 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002230 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002231}
2232
2233
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002234MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2235 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002236 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002237 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002238 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002239 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002240 }
2241 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002242 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002243}
2244
2245
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002246RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002247 NoHandleAllocation ha;
2248 ASSERT(args.length() == 2);
2249
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002250 CONVERT_ARG_CHECKED(String, subject, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002251 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002252 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002253
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002254 uint32_t i = 0;
2255 if (index->IsSmi()) {
2256 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002257 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002258 i = value;
2259 } else {
2260 ASSERT(index->IsHeapNumber());
2261 double value = HeapNumber::cast(index)->value();
2262 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002263 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002264
2265 // Flatten the string. If someone wants to get a char at an index
2266 // in a cons string, it is likely that more indices will be
2267 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002268 Object* flat;
2269 { MaybeObject* maybe_flat = subject->TryFlatten();
2270 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2271 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002272 subject = String::cast(flat);
2273
2274 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002275 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002276 }
2277
2278 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002279}
2280
2281
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002282RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002283 NoHandleAllocation ha;
2284 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002285 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002286}
2287
lrn@chromium.org25156de2010-04-06 13:10:27 +00002288
2289class FixedArrayBuilder {
2290 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002291 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2292 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002293 length_(0),
2294 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002295 // Require a non-zero initial size. Ensures that doubling the size to
2296 // extend the array will work.
2297 ASSERT(initial_capacity > 0);
2298 }
2299
2300 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2301 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002302 length_(0),
2303 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002304 // Require a non-zero initial size. Ensures that doubling the size to
2305 // extend the array will work.
2306 ASSERT(backing_store->length() > 0);
2307 }
2308
2309 bool HasCapacity(int elements) {
2310 int length = array_->length();
2311 int required_length = length_ + elements;
2312 return (length >= required_length);
2313 }
2314
2315 void EnsureCapacity(int elements) {
2316 int length = array_->length();
2317 int required_length = length_ + elements;
2318 if (length < required_length) {
2319 int new_length = length;
2320 do {
2321 new_length *= 2;
2322 } while (new_length < required_length);
2323 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002324 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002325 array_->CopyTo(0, *extended_array, 0, length_);
2326 array_ = extended_array;
2327 }
2328 }
2329
2330 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002331 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002332 ASSERT(length_ < capacity());
2333 array_->set(length_, value);
2334 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002335 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002336 }
2337
2338 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002339 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002340 ASSERT(length_ < capacity());
2341 array_->set(length_, value);
2342 length_++;
2343 }
2344
2345 Handle<FixedArray> array() {
2346 return array_;
2347 }
2348
2349 int length() {
2350 return length_;
2351 }
2352
2353 int capacity() {
2354 return array_->length();
2355 }
2356
2357 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002358 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002359 result_array->set_length(Smi::FromInt(length_));
2360 return result_array;
2361 }
2362
2363 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002364 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002365 target_array->set_length(Smi::FromInt(length_));
2366 return target_array;
2367 }
2368
2369 private:
2370 Handle<FixedArray> array_;
2371 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002372 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002373};
2374
2375
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002376// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002377const int kStringBuilderConcatHelperLengthBits = 11;
2378const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002379
2380template <typename schar>
2381static inline void StringBuilderConcatHelper(String*,
2382 schar*,
2383 FixedArray*,
2384 int);
2385
lrn@chromium.org25156de2010-04-06 13:10:27 +00002386typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2387 StringBuilderSubstringLength;
2388typedef BitField<int,
2389 kStringBuilderConcatHelperLengthBits,
2390 kStringBuilderConcatHelperPositionBits>
2391 StringBuilderSubstringPosition;
2392
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002393
2394class ReplacementStringBuilder {
2395 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002396 ReplacementStringBuilder(Heap* heap,
2397 Handle<String> subject,
2398 int estimated_part_count)
2399 : heap_(heap),
2400 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002401 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002402 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002403 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002404 // Require a non-zero initial size. Ensures that doubling the size to
2405 // extend the array will work.
2406 ASSERT(estimated_part_count > 0);
2407 }
2408
lrn@chromium.org25156de2010-04-06 13:10:27 +00002409 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2410 int from,
2411 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002412 ASSERT(from >= 0);
2413 int length = to - from;
2414 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002415 if (StringBuilderSubstringLength::is_valid(length) &&
2416 StringBuilderSubstringPosition::is_valid(from)) {
2417 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2418 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002419 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002420 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002421 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002422 builder->Add(Smi::FromInt(-length));
2423 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002424 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002425 }
2426
2427
2428 void EnsureCapacity(int elements) {
2429 array_builder_.EnsureCapacity(elements);
2430 }
2431
2432
2433 void AddSubjectSlice(int from, int to) {
2434 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002435 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002436 }
2437
2438
2439 void AddString(Handle<String> string) {
2440 int length = string->length();
2441 ASSERT(length > 0);
2442 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002443 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002444 is_ascii_ = false;
2445 }
2446 IncrementCharacterCount(length);
2447 }
2448
2449
2450 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002451 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002452 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002453 }
2454
2455 Handle<String> joined_string;
2456 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002457 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002458 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002459 char* char_buffer = seq->GetChars();
2460 StringBuilderConcatHelper(*subject_,
2461 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002462 *array_builder_.array(),
2463 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002464 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002465 } else {
2466 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002467 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002468 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002469 uc16* char_buffer = seq->GetChars();
2470 StringBuilderConcatHelper(*subject_,
2471 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002472 *array_builder_.array(),
2473 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002474 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002475 }
2476 return joined_string;
2477 }
2478
2479
2480 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002481 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002482 V8::FatalProcessOutOfMemory("String.replace result too large.");
2483 }
2484 character_count_ += by;
2485 }
2486
lrn@chromium.org25156de2010-04-06 13:10:27 +00002487 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002488 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002489 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002490
lrn@chromium.org25156de2010-04-06 13:10:27 +00002491 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002492 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2493 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002494 }
2495
2496
ager@chromium.org04921a82011-06-27 13:21:41 +00002497 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2498 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002499 }
2500
2501
2502 void AddElement(Object* element) {
2503 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002504 ASSERT(array_builder_.capacity() > array_builder_.length());
2505 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002506 }
2507
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002508 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002509 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002510 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002511 int character_count_;
2512 bool is_ascii_;
2513};
2514
2515
2516class CompiledReplacement {
2517 public:
2518 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002519 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002520
2521 void Compile(Handle<String> replacement,
2522 int capture_count,
2523 int subject_length);
2524
2525 void Apply(ReplacementStringBuilder* builder,
2526 int match_from,
2527 int match_to,
2528 Handle<JSArray> last_match_info);
2529
2530 // Number of distinct parts of the replacement pattern.
2531 int parts() {
2532 return parts_.length();
2533 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002534
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002535 bool simple_hint() {
2536 return simple_hint_;
2537 }
2538
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002539 private:
2540 enum PartType {
2541 SUBJECT_PREFIX = 1,
2542 SUBJECT_SUFFIX,
2543 SUBJECT_CAPTURE,
2544 REPLACEMENT_SUBSTRING,
2545 REPLACEMENT_STRING,
2546
2547 NUMBER_OF_PART_TYPES
2548 };
2549
2550 struct ReplacementPart {
2551 static inline ReplacementPart SubjectMatch() {
2552 return ReplacementPart(SUBJECT_CAPTURE, 0);
2553 }
2554 static inline ReplacementPart SubjectCapture(int capture_index) {
2555 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2556 }
2557 static inline ReplacementPart SubjectPrefix() {
2558 return ReplacementPart(SUBJECT_PREFIX, 0);
2559 }
2560 static inline ReplacementPart SubjectSuffix(int subject_length) {
2561 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2562 }
2563 static inline ReplacementPart ReplacementString() {
2564 return ReplacementPart(REPLACEMENT_STRING, 0);
2565 }
2566 static inline ReplacementPart ReplacementSubString(int from, int to) {
2567 ASSERT(from >= 0);
2568 ASSERT(to > from);
2569 return ReplacementPart(-from, to);
2570 }
2571
2572 // If tag <= 0 then it is the negation of a start index of a substring of
2573 // the replacement pattern, otherwise it's a value from PartType.
2574 ReplacementPart(int tag, int data)
2575 : tag(tag), data(data) {
2576 // Must be non-positive or a PartType value.
2577 ASSERT(tag < NUMBER_OF_PART_TYPES);
2578 }
2579 // Either a value of PartType or a non-positive number that is
2580 // the negation of an index into the replacement string.
2581 int tag;
2582 // The data value's interpretation depends on the value of tag:
2583 // tag == SUBJECT_PREFIX ||
2584 // tag == SUBJECT_SUFFIX: data is unused.
2585 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2586 // tag == REPLACEMENT_SUBSTRING ||
2587 // tag == REPLACEMENT_STRING: data is index into array of substrings
2588 // of the replacement string.
2589 // tag <= 0: Temporary representation of the substring of the replacement
2590 // string ranging over -tag .. data.
2591 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2592 // substring objects.
2593 int data;
2594 };
2595
2596 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002597 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002598 Vector<Char> characters,
2599 int capture_count,
2600 int subject_length) {
2601 int length = characters.length();
2602 int last = 0;
2603 for (int i = 0; i < length; i++) {
2604 Char c = characters[i];
2605 if (c == '$') {
2606 int next_index = i + 1;
2607 if (next_index == length) { // No next character!
2608 break;
2609 }
2610 Char c2 = characters[next_index];
2611 switch (c2) {
2612 case '$':
2613 if (i > last) {
2614 // There is a substring before. Include the first "$".
2615 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2616 last = next_index + 1; // Continue after the second "$".
2617 } else {
2618 // Let the next substring start with the second "$".
2619 last = next_index;
2620 }
2621 i = next_index;
2622 break;
2623 case '`':
2624 if (i > last) {
2625 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2626 }
2627 parts->Add(ReplacementPart::SubjectPrefix());
2628 i = next_index;
2629 last = i + 1;
2630 break;
2631 case '\'':
2632 if (i > last) {
2633 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2634 }
2635 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2636 i = next_index;
2637 last = i + 1;
2638 break;
2639 case '&':
2640 if (i > last) {
2641 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2642 }
2643 parts->Add(ReplacementPart::SubjectMatch());
2644 i = next_index;
2645 last = i + 1;
2646 break;
2647 case '0':
2648 case '1':
2649 case '2':
2650 case '3':
2651 case '4':
2652 case '5':
2653 case '6':
2654 case '7':
2655 case '8':
2656 case '9': {
2657 int capture_ref = c2 - '0';
2658 if (capture_ref > capture_count) {
2659 i = next_index;
2660 continue;
2661 }
2662 int second_digit_index = next_index + 1;
2663 if (second_digit_index < length) {
2664 // Peek ahead to see if we have two digits.
2665 Char c3 = characters[second_digit_index];
2666 if ('0' <= c3 && c3 <= '9') { // Double digits.
2667 int double_digit_ref = capture_ref * 10 + c3 - '0';
2668 if (double_digit_ref <= capture_count) {
2669 next_index = second_digit_index;
2670 capture_ref = double_digit_ref;
2671 }
2672 }
2673 }
2674 if (capture_ref > 0) {
2675 if (i > last) {
2676 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2677 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002678 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002679 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2680 last = next_index + 1;
2681 }
2682 i = next_index;
2683 break;
2684 }
2685 default:
2686 i = next_index;
2687 break;
2688 }
2689 }
2690 }
2691 if (length > last) {
2692 if (last == 0) {
2693 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002694 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002695 } else {
2696 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2697 }
2698 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002699 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002700 }
2701
2702 ZoneList<ReplacementPart> parts_;
2703 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002704 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002705};
2706
2707
2708void CompiledReplacement::Compile(Handle<String> replacement,
2709 int capture_count,
2710 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002711 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002712 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002713 String::FlatContent content = replacement->GetFlatContent();
2714 ASSERT(content.IsFlat());
2715 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002716 simple_hint_ = ParseReplacementPattern(&parts_,
2717 content.ToAsciiVector(),
2718 capture_count,
2719 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002720 } else {
2721 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002722 simple_hint_ = ParseReplacementPattern(&parts_,
2723 content.ToUC16Vector(),
2724 capture_count,
2725 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002726 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002727 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002728 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002729 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002730 int substring_index = 0;
2731 for (int i = 0, n = parts_.length(); i < n; i++) {
2732 int tag = parts_[i].tag;
2733 if (tag <= 0) { // A replacement string slice.
2734 int from = -tag;
2735 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002736 replacement_substrings_.Add(
2737 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002738 parts_[i].tag = REPLACEMENT_SUBSTRING;
2739 parts_[i].data = substring_index;
2740 substring_index++;
2741 } else if (tag == REPLACEMENT_STRING) {
2742 replacement_substrings_.Add(replacement);
2743 parts_[i].data = substring_index;
2744 substring_index++;
2745 }
2746 }
2747}
2748
2749
2750void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2751 int match_from,
2752 int match_to,
2753 Handle<JSArray> last_match_info) {
2754 for (int i = 0, n = parts_.length(); i < n; i++) {
2755 ReplacementPart part = parts_[i];
2756 switch (part.tag) {
2757 case SUBJECT_PREFIX:
2758 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2759 break;
2760 case SUBJECT_SUFFIX: {
2761 int subject_length = part.data;
2762 if (match_to < subject_length) {
2763 builder->AddSubjectSlice(match_to, subject_length);
2764 }
2765 break;
2766 }
2767 case SUBJECT_CAPTURE: {
2768 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002769 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002770 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2771 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2772 if (from >= 0 && to > from) {
2773 builder->AddSubjectSlice(from, to);
2774 }
2775 break;
2776 }
2777 case REPLACEMENT_SUBSTRING:
2778 case REPLACEMENT_STRING:
2779 builder->AddString(replacement_substrings_[part.data]);
2780 break;
2781 default:
2782 UNREACHABLE();
2783 }
2784 }
2785}
2786
2787
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002788void FindAsciiStringIndices(Vector<const char> subject,
2789 char pattern,
2790 ZoneList<int>* indices,
2791 unsigned int limit) {
2792 ASSERT(limit > 0);
2793 // Collect indices of pattern in subject using memchr.
2794 // Stop after finding at most limit values.
2795 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2796 const char* subject_end = subject_start + subject.length();
2797 const char* pos = subject_start;
2798 while (limit > 0) {
2799 pos = reinterpret_cast<const char*>(
2800 memchr(pos, pattern, subject_end - pos));
2801 if (pos == NULL) return;
2802 indices->Add(static_cast<int>(pos - subject_start));
2803 pos++;
2804 limit--;
2805 }
2806}
2807
2808
2809template <typename SubjectChar, typename PatternChar>
2810void FindStringIndices(Isolate* isolate,
2811 Vector<const SubjectChar> subject,
2812 Vector<const PatternChar> pattern,
2813 ZoneList<int>* indices,
2814 unsigned int limit) {
2815 ASSERT(limit > 0);
2816 // Collect indices of pattern in subject.
2817 // Stop after finding at most limit values.
2818 int pattern_length = pattern.length();
2819 int index = 0;
2820 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2821 while (limit > 0) {
2822 index = search.Search(subject, index);
2823 if (index < 0) return;
2824 indices->Add(index);
2825 index += pattern_length;
2826 limit--;
2827 }
2828}
2829
2830
2831void FindStringIndicesDispatch(Isolate* isolate,
2832 String* subject,
2833 String* pattern,
2834 ZoneList<int>* indices,
2835 unsigned int limit) {
2836 {
2837 AssertNoAllocation no_gc;
2838 String::FlatContent subject_content = subject->GetFlatContent();
2839 String::FlatContent pattern_content = pattern->GetFlatContent();
2840 ASSERT(subject_content.IsFlat());
2841 ASSERT(pattern_content.IsFlat());
2842 if (subject_content.IsAscii()) {
2843 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2844 if (pattern_content.IsAscii()) {
2845 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2846 if (pattern_vector.length() == 1) {
2847 FindAsciiStringIndices(subject_vector,
2848 pattern_vector[0],
2849 indices,
2850 limit);
2851 } else {
2852 FindStringIndices(isolate,
2853 subject_vector,
2854 pattern_vector,
2855 indices,
2856 limit);
2857 }
2858 } else {
2859 FindStringIndices(isolate,
2860 subject_vector,
2861 pattern_content.ToUC16Vector(),
2862 indices,
2863 limit);
2864 }
2865 } else {
2866 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002867 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002868 FindStringIndices(isolate,
2869 subject_vector,
2870 pattern_content.ToAsciiVector(),
2871 indices,
2872 limit);
2873 } else {
2874 FindStringIndices(isolate,
2875 subject_vector,
2876 pattern_content.ToUC16Vector(),
2877 indices,
2878 limit);
2879 }
2880 }
2881 }
2882}
2883
2884
2885template<typename ResultSeqString>
2886MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2887 Isolate* isolate,
2888 Handle<String> subject,
2889 Handle<JSRegExp> pattern_regexp,
2890 Handle<String> replacement) {
2891 ASSERT(subject->IsFlat());
2892 ASSERT(replacement->IsFlat());
2893
2894 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2895 ZoneList<int> indices(8);
2896 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2897 String* pattern =
2898 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2899 int subject_len = subject->length();
2900 int pattern_len = pattern->length();
2901 int replacement_len = replacement->length();
2902
2903 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2904
2905 int matches = indices.length();
2906 if (matches == 0) return *subject;
2907
2908 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2909 int subject_pos = 0;
2910 int result_pos = 0;
2911
2912 Handle<ResultSeqString> result;
2913 if (ResultSeqString::kHasAsciiEncoding) {
2914 result = Handle<ResultSeqString>::cast(
2915 isolate->factory()->NewRawAsciiString(result_len));
2916 } else {
2917 result = Handle<ResultSeqString>::cast(
2918 isolate->factory()->NewRawTwoByteString(result_len));
2919 }
2920
2921 for (int i = 0; i < matches; i++) {
2922 // Copy non-matched subject content.
2923 if (subject_pos < indices.at(i)) {
2924 String::WriteToFlat(*subject,
2925 result->GetChars() + result_pos,
2926 subject_pos,
2927 indices.at(i));
2928 result_pos += indices.at(i) - subject_pos;
2929 }
2930
2931 // Replace match.
2932 if (replacement_len > 0) {
2933 String::WriteToFlat(*replacement,
2934 result->GetChars() + result_pos,
2935 0,
2936 replacement_len);
2937 result_pos += replacement_len;
2938 }
2939
2940 subject_pos = indices.at(i) + pattern_len;
2941 }
2942 // Add remaining subject content at the end.
2943 if (subject_pos < subject_len) {
2944 String::WriteToFlat(*subject,
2945 result->GetChars() + result_pos,
2946 subject_pos,
2947 subject_len);
2948 }
2949 return *result;
2950}
2951
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002952
lrn@chromium.org303ada72010-10-27 09:33:13 +00002953MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002954 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002955 String* subject,
2956 JSRegExp* regexp,
2957 String* replacement,
2958 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002959 ASSERT(subject->IsFlat());
2960 ASSERT(replacement->IsFlat());
2961
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002962 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002963
2964 int length = subject->length();
2965 Handle<String> subject_handle(subject);
2966 Handle<JSRegExp> regexp_handle(regexp);
2967 Handle<String> replacement_handle(replacement);
2968 Handle<JSArray> last_match_info_handle(last_match_info);
2969 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2970 subject_handle,
2971 0,
2972 last_match_info_handle);
2973 if (match.is_null()) {
2974 return Failure::Exception();
2975 }
2976 if (match->IsNull()) {
2977 return *subject_handle;
2978 }
2979
2980 int capture_count = regexp_handle->CaptureCount();
2981
2982 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002983 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002984 CompiledReplacement compiled_replacement;
2985 compiled_replacement.Compile(replacement_handle,
2986 capture_count,
2987 length);
2988
2989 bool is_global = regexp_handle->GetFlags().is_global();
2990
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002991 // Shortcut for simple non-regexp global replacements
2992 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002993 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002994 compiled_replacement.simple_hint()) {
2995 if (subject_handle->HasOnlyAsciiChars() &&
2996 replacement_handle->HasOnlyAsciiChars()) {
2997 return StringReplaceStringWithString<SeqAsciiString>(
2998 isolate, subject_handle, regexp_handle, replacement_handle);
2999 } else {
3000 return StringReplaceStringWithString<SeqTwoByteString>(
3001 isolate, subject_handle, regexp_handle, replacement_handle);
3002 }
3003 }
3004
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003005 // Guessing the number of parts that the final result string is built
3006 // from. Global regexps can match any number of times, so we guess
3007 // conservatively.
3008 int expected_parts =
3009 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003010 ReplacementStringBuilder builder(isolate->heap(),
3011 subject_handle,
3012 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003013
3014 // Index of end of last match.
3015 int prev = 0;
3016
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003017 // Number of parts added by compiled replacement plus preceeding
3018 // string and possibly suffix after last match. It is possible for
3019 // all components to use two elements when encoded as two smis.
3020 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003021 bool matched = true;
3022 do {
3023 ASSERT(last_match_info_handle->HasFastElements());
3024 // Increase the capacity of the builder before entering local handle-scope,
3025 // so its internal buffer can safely allocate a new handle if it grows.
3026 builder.EnsureCapacity(parts_added_per_loop);
3027
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003028 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003029 int start, end;
3030 {
3031 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003032 FixedArray* match_info_array =
3033 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003034
3035 ASSERT_EQ(capture_count * 2 + 2,
3036 RegExpImpl::GetLastCaptureCount(match_info_array));
3037 start = RegExpImpl::GetCapture(match_info_array, 0);
3038 end = RegExpImpl::GetCapture(match_info_array, 1);
3039 }
3040
3041 if (prev < start) {
3042 builder.AddSubjectSlice(prev, start);
3043 }
3044 compiled_replacement.Apply(&builder,
3045 start,
3046 end,
3047 last_match_info_handle);
3048 prev = end;
3049
3050 // Only continue checking for global regexps.
3051 if (!is_global) break;
3052
3053 // Continue from where the match ended, unless it was an empty match.
3054 int next = end;
3055 if (start == end) {
3056 next = end + 1;
3057 if (next > length) break;
3058 }
3059
3060 match = RegExpImpl::Exec(regexp_handle,
3061 subject_handle,
3062 next,
3063 last_match_info_handle);
3064 if (match.is_null()) {
3065 return Failure::Exception();
3066 }
3067 matched = !match->IsNull();
3068 } while (matched);
3069
3070 if (prev < length) {
3071 builder.AddSubjectSlice(prev, length);
3072 }
3073
3074 return *(builder.ToString());
3075}
3076
3077
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003078template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003079MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003080 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003081 String* subject,
3082 JSRegExp* regexp,
3083 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003084 ASSERT(subject->IsFlat());
3085
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003086 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003087
3088 Handle<String> subject_handle(subject);
3089 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003090
3091 // Shortcut for simple non-regexp global replacements
3092 if (regexp_handle->GetFlags().is_global() &&
3093 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3094 Handle<String> empty_string_handle(HEAP->empty_string());
3095 if (subject_handle->HasOnlyAsciiChars()) {
3096 return StringReplaceStringWithString<SeqAsciiString>(
3097 isolate, subject_handle, regexp_handle, empty_string_handle);
3098 } else {
3099 return StringReplaceStringWithString<SeqTwoByteString>(
3100 isolate, subject_handle, regexp_handle, empty_string_handle);
3101 }
3102 }
3103
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003104 Handle<JSArray> last_match_info_handle(last_match_info);
3105 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3106 subject_handle,
3107 0,
3108 last_match_info_handle);
3109 if (match.is_null()) return Failure::Exception();
3110 if (match->IsNull()) return *subject_handle;
3111
3112 ASSERT(last_match_info_handle->HasFastElements());
3113
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003114 int start, end;
3115 {
3116 AssertNoAllocation match_info_array_is_not_in_a_handle;
3117 FixedArray* match_info_array =
3118 FixedArray::cast(last_match_info_handle->elements());
3119
3120 start = RegExpImpl::GetCapture(match_info_array, 0);
3121 end = RegExpImpl::GetCapture(match_info_array, 1);
3122 }
3123
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003124 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003125 int new_length = length - (end - start);
3126 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003127 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003128 }
3129 Handle<ResultSeqString> answer;
3130 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003131 answer = Handle<ResultSeqString>::cast(
3132 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003133 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003134 answer = Handle<ResultSeqString>::cast(
3135 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003136 }
3137
3138 // If the regexp isn't global, only match once.
3139 if (!regexp_handle->GetFlags().is_global()) {
3140 if (start > 0) {
3141 String::WriteToFlat(*subject_handle,
3142 answer->GetChars(),
3143 0,
3144 start);
3145 }
3146 if (end < length) {
3147 String::WriteToFlat(*subject_handle,
3148 answer->GetChars() + start,
3149 end,
3150 length);
3151 }
3152 return *answer;
3153 }
3154
3155 int prev = 0; // Index of end of last match.
3156 int next = 0; // Start of next search (prev unless last match was empty).
3157 int position = 0;
3158
3159 do {
3160 if (prev < start) {
3161 // Add substring subject[prev;start] to answer string.
3162 String::WriteToFlat(*subject_handle,
3163 answer->GetChars() + position,
3164 prev,
3165 start);
3166 position += start - prev;
3167 }
3168 prev = end;
3169 next = end;
3170 // Continue from where the match ended, unless it was an empty match.
3171 if (start == end) {
3172 next++;
3173 if (next > length) break;
3174 }
3175 match = RegExpImpl::Exec(regexp_handle,
3176 subject_handle,
3177 next,
3178 last_match_info_handle);
3179 if (match.is_null()) return Failure::Exception();
3180 if (match->IsNull()) break;
3181
3182 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003183 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003184 {
3185 AssertNoAllocation match_info_array_is_not_in_a_handle;
3186 FixedArray* match_info_array =
3187 FixedArray::cast(last_match_info_handle->elements());
3188 start = RegExpImpl::GetCapture(match_info_array, 0);
3189 end = RegExpImpl::GetCapture(match_info_array, 1);
3190 }
3191 } while (true);
3192
3193 if (prev < length) {
3194 // Add substring subject[prev;length] to answer string.
3195 String::WriteToFlat(*subject_handle,
3196 answer->GetChars() + position,
3197 prev,
3198 length);
3199 position += length - prev;
3200 }
3201
3202 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003203 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003204 }
3205
3206 // Shorten string and fill
3207 int string_size = ResultSeqString::SizeFor(position);
3208 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3209 int delta = allocated_string_size - string_size;
3210
3211 answer->set_length(position);
3212 if (delta == 0) return *answer;
3213
3214 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003215 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003216 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003217 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003218 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003219
3220 return *answer;
3221}
3222
3223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003224RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003225 ASSERT(args.length() == 4);
3226
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003227 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003228 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003229 Object* flat_subject;
3230 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3231 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3232 return maybe_flat_subject;
3233 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003234 }
3235 subject = String::cast(flat_subject);
3236 }
3237
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003238 CONVERT_ARG_CHECKED(String, replacement, 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003239 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003240 Object* flat_replacement;
3241 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3242 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3243 return maybe_flat_replacement;
3244 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003245 }
3246 replacement = String::cast(flat_replacement);
3247 }
3248
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003249 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3250 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003251
3252 ASSERT(last_match_info->HasFastElements());
3253
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003254 if (replacement->length() == 0) {
3255 if (subject->HasOnlyAsciiChars()) {
3256 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003257 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003258 } else {
3259 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003260 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003261 }
3262 }
3263
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003264 return StringReplaceRegExpWithString(isolate,
3265 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003266 regexp,
3267 replacement,
3268 last_match_info);
3269}
3270
3271
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003272Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3273 Handle<String> subject,
3274 Handle<String> search,
3275 Handle<String> replace,
3276 bool* found,
3277 int recursion_limit) {
3278 if (recursion_limit == 0) return Handle<String>::null();
3279 if (subject->IsConsString()) {
3280 ConsString* cons = ConsString::cast(*subject);
3281 Handle<String> first = Handle<String>(cons->first());
3282 Handle<String> second = Handle<String>(cons->second());
3283 Handle<String> new_first =
3284 StringReplaceOneCharWithString(isolate,
3285 first,
3286 search,
3287 replace,
3288 found,
3289 recursion_limit - 1);
3290 if (*found) return isolate->factory()->NewConsString(new_first, second);
3291 if (new_first.is_null()) return new_first;
3292
3293 Handle<String> new_second =
3294 StringReplaceOneCharWithString(isolate,
3295 second,
3296 search,
3297 replace,
3298 found,
3299 recursion_limit - 1);
3300 if (*found) return isolate->factory()->NewConsString(first, new_second);
3301 if (new_second.is_null()) return new_second;
3302
3303 return subject;
3304 } else {
3305 int index = StringMatch(isolate, subject, search, 0);
3306 if (index == -1) return subject;
3307 *found = true;
3308 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3309 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3310 Handle<String> second =
3311 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3312 return isolate->factory()->NewConsString(cons1, second);
3313 }
3314}
3315
3316
3317RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3318 ASSERT(args.length() == 3);
3319 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003320 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3321 CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
3322 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003323
3324 // If the cons string tree is too deep, we simply abort the recursion and
3325 // retry with a flattened subject string.
3326 const int kRecursionLimit = 0x1000;
3327 bool found = false;
3328 Handle<String> result =
3329 Runtime::StringReplaceOneCharWithString(isolate,
3330 subject,
3331 search,
3332 replace,
3333 &found,
3334 kRecursionLimit);
3335 if (!result.is_null()) return *result;
3336 return *Runtime::StringReplaceOneCharWithString(isolate,
3337 FlattenGetString(subject),
3338 search,
3339 replace,
3340 &found,
3341 kRecursionLimit);
3342}
3343
3344
ager@chromium.org7c537e22008-10-16 08:43:32 +00003345// Perform string match of pattern on subject, starting at start index.
3346// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003347// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003348int Runtime::StringMatch(Isolate* isolate,
3349 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003350 Handle<String> pat,
3351 int start_index) {
3352 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003353 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003354
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003355 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003356 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003357
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003358 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003359 if (start_index + pattern_length > subject_length) return -1;
3360
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003361 if (!sub->IsFlat()) FlattenString(sub);
3362 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003363
ager@chromium.org7c537e22008-10-16 08:43:32 +00003364 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003365 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003366 String::FlatContent seq_sub = sub->GetFlatContent();
3367 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003368
ager@chromium.org7c537e22008-10-16 08:43:32 +00003369 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003370 if (seq_pat.IsAscii()) {
3371 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3372 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003373 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003374 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003375 pat_vector,
3376 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003377 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003378 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003379 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003380 pat_vector,
3381 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003382 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003383 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3384 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003385 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003386 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003387 pat_vector,
3388 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003389 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003390 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003391 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003392 pat_vector,
3393 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003394}
3395
3396
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003397RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003398 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003399 ASSERT(args.length() == 3);
3400
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003401 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3402 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003403
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003404 Object* index = args[2];
3405 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003406 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003407
ager@chromium.org870a0b62008-11-04 11:43:05 +00003408 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003409 int position =
3410 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003411 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003412}
3413
3414
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003415template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003416static int StringMatchBackwards(Vector<const schar> subject,
3417 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003418 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003419 int pattern_length = pattern.length();
3420 ASSERT(pattern_length >= 1);
3421 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003422
3423 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003424 for (int i = 0; i < pattern_length; i++) {
3425 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003426 if (c > String::kMaxAsciiCharCode) {
3427 return -1;
3428 }
3429 }
3430 }
3431
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003432 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003433 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003434 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003435 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003436 while (j < pattern_length) {
3437 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003438 break;
3439 }
3440 j++;
3441 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003442 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003443 return i;
3444 }
3445 }
3446 return -1;
3447}
3448
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003449RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003450 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003451 ASSERT(args.length() == 3);
3452
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003453 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3454 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003455
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003456 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003457 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003458 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003459
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003460 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003461 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003462
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003463 if (start_index + pat_length > sub_length) {
3464 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003465 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003466
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003467 if (pat_length == 0) {
3468 return Smi::FromInt(start_index);
3469 }
3470
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003471 if (!sub->IsFlat()) FlattenString(sub);
3472 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003473
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003474 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003475 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3476
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003477 String::FlatContent sub_content = sub->GetFlatContent();
3478 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003479
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003480 if (pat_content.IsAscii()) {
3481 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3482 if (sub_content.IsAscii()) {
3483 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003484 pat_vector,
3485 start_index);
3486 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003487 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003488 pat_vector,
3489 start_index);
3490 }
3491 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003492 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3493 if (sub_content.IsAscii()) {
3494 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003495 pat_vector,
3496 start_index);
3497 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003498 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003499 pat_vector,
3500 start_index);
3501 }
3502 }
3503
3504 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003505}
3506
3507
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003508RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003509 NoHandleAllocation ha;
3510 ASSERT(args.length() == 2);
3511
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003512 CONVERT_ARG_CHECKED(String, str1, 0);
3513 CONVERT_ARG_CHECKED(String, str2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003514
3515 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003516 int str1_length = str1->length();
3517 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003518
3519 // Decide trivial cases without flattening.
3520 if (str1_length == 0) {
3521 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3522 return Smi::FromInt(-str2_length);
3523 } else {
3524 if (str2_length == 0) return Smi::FromInt(str1_length);
3525 }
3526
3527 int end = str1_length < str2_length ? str1_length : str2_length;
3528
3529 // No need to flatten if we are going to find the answer on the first
3530 // character. At this point we know there is at least one character
3531 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003532 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003533 if (d != 0) return Smi::FromInt(d);
3534
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003535 str1->TryFlatten();
3536 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003537
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003538 StringInputBuffer& buf1 =
3539 *isolate->runtime_state()->string_locale_compare_buf1();
3540 StringInputBuffer& buf2 =
3541 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003542
3543 buf1.Reset(str1);
3544 buf2.Reset(str2);
3545
3546 for (int i = 0; i < end; i++) {
3547 uint16_t char1 = buf1.GetNext();
3548 uint16_t char2 = buf2.GetNext();
3549 if (char1 != char2) return Smi::FromInt(char1 - char2);
3550 }
3551
3552 return Smi::FromInt(str1_length - str2_length);
3553}
3554
3555
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003556RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003557 NoHandleAllocation ha;
3558 ASSERT(args.length() == 3);
3559
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003560 CONVERT_ARG_CHECKED(String, value, 0);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003561 int start, end;
3562 // We have a fast integer-only case here to avoid a conversion to double in
3563 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003564 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3565 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3566 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3567 start = from_number;
3568 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003569 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003570 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3571 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003572 start = FastD2I(from_number);
3573 end = FastD2I(to_number);
3574 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003575 RUNTIME_ASSERT(end >= start);
3576 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003577 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003578 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003579 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003580}
3581
3582
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003583RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003584 ASSERT_EQ(3, args.length());
3585
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003586 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3587 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
3588 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
ager@chromium.org41826e72009-03-30 13:30:57 +00003589 HandleScope handles;
3590
3591 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3592
3593 if (match.is_null()) {
3594 return Failure::Exception();
3595 }
3596 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003597 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003598 }
3599 int length = subject->length();
3600
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003601 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003602 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003603 int start;
3604 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003605 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003606 {
3607 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003608 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003609 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3610 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3611 }
3612 offsets.Add(start);
3613 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003614 if (start == end) if (++end > length) break;
3615 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003616 if (match.is_null()) {
3617 return Failure::Exception();
3618 }
3619 } while (!match->IsNull());
3620 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003621 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003622 Handle<String> substring = isolate->factory()->
3623 NewSubString(subject, offsets.at(0), offsets.at(1));
3624 elements->set(0, *substring);
3625 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003626 int from = offsets.at(i * 2);
3627 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003628 Handle<String> substring = isolate->factory()->
3629 NewProperSubString(subject, from, to);
3630 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003631 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003632 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003633 result->set_length(Smi::FromInt(matches));
3634 return *result;
3635}
3636
3637
lrn@chromium.org25156de2010-04-06 13:10:27 +00003638// Two smis before and after the match, for very long strings.
3639const int kMaxBuilderEntriesPerRegExpMatch = 5;
3640
3641
3642static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3643 Handle<JSArray> last_match_info,
3644 int match_start,
3645 int match_end) {
3646 // Fill last_match_info with a single capture.
3647 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3648 AssertNoAllocation no_gc;
3649 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3650 RegExpImpl::SetLastCaptureCount(elements, 2);
3651 RegExpImpl::SetLastInput(elements, *subject);
3652 RegExpImpl::SetLastSubject(elements, *subject);
3653 RegExpImpl::SetCapture(elements, 0, match_start);
3654 RegExpImpl::SetCapture(elements, 1, match_end);
3655}
3656
3657
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003658template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003659static bool SearchStringMultiple(Isolate* isolate,
3660 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003661 Vector<const PatternChar> pattern,
3662 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003663 FixedArrayBuilder* builder,
3664 int* match_pos) {
3665 int pos = *match_pos;
3666 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003667 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003668 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003669 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003670 while (pos <= max_search_start) {
3671 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3672 *match_pos = pos;
3673 return false;
3674 }
3675 // Position of end of previous match.
3676 int match_end = pos + pattern_length;
3677 int new_pos = search.Search(subject, match_end);
3678 if (new_pos >= 0) {
3679 // A match.
3680 if (new_pos > match_end) {
3681 ReplacementStringBuilder::AddSubjectSlice(builder,
3682 match_end,
3683 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003684 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003685 pos = new_pos;
3686 builder->Add(pattern_string);
3687 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003688 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003689 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003690 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003691
lrn@chromium.org25156de2010-04-06 13:10:27 +00003692 if (pos < max_search_start) {
3693 ReplacementStringBuilder::AddSubjectSlice(builder,
3694 pos + pattern_length,
3695 subject_length);
3696 }
3697 *match_pos = pos;
3698 return true;
3699}
3700
3701
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003702static bool SearchStringMultiple(Isolate* isolate,
3703 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003704 Handle<String> pattern,
3705 Handle<JSArray> last_match_info,
3706 FixedArrayBuilder* builder) {
3707 ASSERT(subject->IsFlat());
3708 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003709
3710 // Treating as if a previous match was before first character.
3711 int match_pos = -pattern->length();
3712
3713 for (;;) { // Break when search complete.
3714 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3715 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003716 String::FlatContent subject_content = subject->GetFlatContent();
3717 String::FlatContent pattern_content = pattern->GetFlatContent();
3718 if (subject_content.IsAscii()) {
3719 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3720 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003721 if (SearchStringMultiple(isolate,
3722 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003723 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003724 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003725 builder,
3726 &match_pos)) break;
3727 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003728 if (SearchStringMultiple(isolate,
3729 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003730 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003731 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003732 builder,
3733 &match_pos)) break;
3734 }
3735 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003736 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3737 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003738 if (SearchStringMultiple(isolate,
3739 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003740 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003741 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003742 builder,
3743 &match_pos)) break;
3744 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003745 if (SearchStringMultiple(isolate,
3746 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003747 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003748 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003749 builder,
3750 &match_pos)) break;
3751 }
3752 }
3753 }
3754
3755 if (match_pos >= 0) {
3756 SetLastMatchInfoNoCaptures(subject,
3757 last_match_info,
3758 match_pos,
3759 match_pos + pattern->length());
3760 return true;
3761 }
3762 return false; // No matches at all.
3763}
3764
3765
3766static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003767 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003768 Handle<String> subject,
3769 Handle<JSRegExp> regexp,
3770 Handle<JSArray> last_match_array,
3771 FixedArrayBuilder* builder) {
3772 ASSERT(subject->IsFlat());
3773 int match_start = -1;
3774 int match_end = 0;
3775 int pos = 0;
3776 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3777 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3778
ulan@chromium.org812308e2012-02-29 15:58:45 +00003779 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003780 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003781 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003782 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003783
3784 for (;;) { // Break on failure, return on exception.
3785 RegExpImpl::IrregexpResult result =
3786 RegExpImpl::IrregexpExecOnce(regexp,
3787 subject,
3788 pos,
3789 register_vector);
3790 if (result == RegExpImpl::RE_SUCCESS) {
3791 match_start = register_vector[0];
3792 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3793 if (match_end < match_start) {
3794 ReplacementStringBuilder::AddSubjectSlice(builder,
3795 match_end,
3796 match_start);
3797 }
3798 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003799 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003800 if (!first) {
3801 builder->Add(*isolate->factory()->NewProperSubString(subject,
3802 match_start,
3803 match_end));
3804 } else {
3805 builder->Add(*isolate->factory()->NewSubString(subject,
3806 match_start,
3807 match_end));
3808 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003809 if (match_start != match_end) {
3810 pos = match_end;
3811 } else {
3812 pos = match_end + 1;
3813 if (pos > subject_length) break;
3814 }
3815 } else if (result == RegExpImpl::RE_FAILURE) {
3816 break;
3817 } else {
3818 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3819 return result;
3820 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003821 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003822 }
3823
3824 if (match_start >= 0) {
3825 if (match_end < subject_length) {
3826 ReplacementStringBuilder::AddSubjectSlice(builder,
3827 match_end,
3828 subject_length);
3829 }
3830 SetLastMatchInfoNoCaptures(subject,
3831 last_match_array,
3832 match_start,
3833 match_end);
3834 return RegExpImpl::RE_SUCCESS;
3835 } else {
3836 return RegExpImpl::RE_FAILURE; // No matches at all.
3837 }
3838}
3839
3840
3841static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003842 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003843 Handle<String> subject,
3844 Handle<JSRegExp> regexp,
3845 Handle<JSArray> last_match_array,
3846 FixedArrayBuilder* builder) {
3847
3848 ASSERT(subject->IsFlat());
3849 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3850 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3851
ulan@chromium.org812308e2012-02-29 15:58:45 +00003852 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003853 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003854
3855 RegExpImpl::IrregexpResult result =
3856 RegExpImpl::IrregexpExecOnce(regexp,
3857 subject,
3858 0,
3859 register_vector);
3860
3861 int capture_count = regexp->CaptureCount();
3862 int subject_length = subject->length();
3863
3864 // Position to search from.
3865 int pos = 0;
3866 // End of previous match. Differs from pos if match was empty.
3867 int match_end = 0;
3868 if (result == RegExpImpl::RE_SUCCESS) {
3869 // Need to keep a copy of the previous match for creating last_match_info
3870 // at the end, so we have two vectors that we swap between.
ulan@chromium.org812308e2012-02-29 15:58:45 +00003871 OffsetsVector registers2(required_registers, isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003872 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003873 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003874 do {
3875 int match_start = register_vector[0];
3876 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3877 if (match_end < match_start) {
3878 ReplacementStringBuilder::AddSubjectSlice(builder,
3879 match_end,
3880 match_start);
3881 }
3882 match_end = register_vector[1];
3883
3884 {
3885 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003886 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003887 // Arguments array to replace function is match, captures, index and
3888 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003889 Handle<FixedArray> elements =
3890 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003891 Handle<String> match;
3892 if (!first) {
3893 match = isolate->factory()->NewProperSubString(subject,
3894 match_start,
3895 match_end);
3896 } else {
3897 match = isolate->factory()->NewSubString(subject,
3898 match_start,
3899 match_end);
3900 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003901 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003902 for (int i = 1; i <= capture_count; i++) {
3903 int start = register_vector[i * 2];
3904 if (start >= 0) {
3905 int end = register_vector[i * 2 + 1];
3906 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003907 Handle<String> substring;
3908 if (!first) {
3909 substring = isolate->factory()->NewProperSubString(subject,
3910 start,
3911 end);
3912 } else {
3913 substring = isolate->factory()->NewSubString(subject, start, end);
3914 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003915 elements->set(i, *substring);
3916 } else {
3917 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003918 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003919 }
3920 }
3921 elements->set(capture_count + 1, Smi::FromInt(match_start));
3922 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003923 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003924 }
3925 // Swap register vectors, so the last successful match is in
3926 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003927 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003928 prev_register_vector = register_vector;
3929 register_vector = tmp;
3930
3931 if (match_end > match_start) {
3932 pos = match_end;
3933 } else {
3934 pos = match_end + 1;
3935 if (pos > subject_length) {
3936 break;
3937 }
3938 }
3939
3940 result = RegExpImpl::IrregexpExecOnce(regexp,
3941 subject,
3942 pos,
3943 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003944 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003945 } while (result == RegExpImpl::RE_SUCCESS);
3946
3947 if (result != RegExpImpl::RE_EXCEPTION) {
3948 // Finished matching, with at least one match.
3949 if (match_end < subject_length) {
3950 ReplacementStringBuilder::AddSubjectSlice(builder,
3951 match_end,
3952 subject_length);
3953 }
3954
3955 int last_match_capture_count = (capture_count + 1) * 2;
3956 int last_match_array_size =
3957 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3958 last_match_array->EnsureSize(last_match_array_size);
3959 AssertNoAllocation no_gc;
3960 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3961 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3962 RegExpImpl::SetLastSubject(elements, *subject);
3963 RegExpImpl::SetLastInput(elements, *subject);
3964 for (int i = 0; i < last_match_capture_count; i++) {
3965 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3966 }
3967 return RegExpImpl::RE_SUCCESS;
3968 }
3969 }
3970 // No matches at all, return failure or exception result directly.
3971 return result;
3972}
3973
3974
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003975RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003976 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003977 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003978
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003979 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003980 if (!subject->IsFlat()) FlattenString(subject);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003981 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
3982 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
3983 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003984
3985 ASSERT(last_match_info->HasFastElements());
3986 ASSERT(regexp->GetFlags().is_global());
3987 Handle<FixedArray> result_elements;
3988 if (result_array->HasFastElements()) {
3989 result_elements =
3990 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003991 }
3992 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003993 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003994 }
3995 FixedArrayBuilder builder(result_elements);
3996
3997 if (regexp->TypeTag() == JSRegExp::ATOM) {
3998 Handle<String> pattern(
3999 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004000 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004001 if (SearchStringMultiple(isolate, subject, pattern,
4002 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00004003 return *builder.ToJSArray(result_array);
4004 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004005 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004006 }
4007
4008 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
4009
4010 RegExpImpl::IrregexpResult result;
4011 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004012 result = SearchRegExpNoCaptureMultiple(isolate,
4013 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00004014 regexp,
4015 last_match_info,
4016 &builder);
4017 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004018 result = SearchRegExpMultiple(isolate,
4019 subject,
4020 regexp,
4021 last_match_info,
4022 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004023 }
4024 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004025 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004026 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
4027 return Failure::Exception();
4028}
4029
4030
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004031RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004032 NoHandleAllocation ha;
4033 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004034 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004035 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004036
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004037 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004038 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004039 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004040 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004041 // Character array used for conversion.
4042 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004043 return isolate->heap()->
4044 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004045 }
4046 }
4047
4048 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004049 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004050 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004051 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004052 }
4053 if (isinf(value)) {
4054 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004055 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004056 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004057 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004058 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004059 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004060 MaybeObject* result =
4061 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004062 DeleteArray(str);
4063 return result;
4064}
4065
4066
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004067RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004068 NoHandleAllocation ha;
4069 ASSERT(args.length() == 2);
4070
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004071 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004072 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004073 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004074 }
4075 if (isinf(value)) {
4076 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004077 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004078 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004079 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004080 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004081 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004082 int f = FastD2I(f_number);
4083 RUNTIME_ASSERT(f >= 0);
4084 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004085 MaybeObject* res =
4086 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004087 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004088 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004089}
4090
4091
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004092RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004093 NoHandleAllocation ha;
4094 ASSERT(args.length() == 2);
4095
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004096 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004097 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004098 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004099 }
4100 if (isinf(value)) {
4101 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004102 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004103 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004104 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004105 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004106 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004107 int f = FastD2I(f_number);
4108 RUNTIME_ASSERT(f >= -1 && f <= 20);
4109 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004110 MaybeObject* res =
4111 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004113 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004114}
4115
4116
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004117RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004118 NoHandleAllocation ha;
4119 ASSERT(args.length() == 2);
4120
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004121 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004122 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004123 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004124 }
4125 if (isinf(value)) {
4126 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004127 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004128 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004129 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004130 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004131 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004132 int f = FastD2I(f_number);
4133 RUNTIME_ASSERT(f >= 1 && f <= 21);
4134 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004135 MaybeObject* res =
4136 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004137 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004138 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004139}
4140
4141
4142// Returns a single character string where first character equals
4143// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004144static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004145 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004146 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004147 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004148 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004149 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004150 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004151}
4152
4153
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004154MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4155 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004156 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004157 // Handle [] indexing on Strings
4158 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004159 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4160 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004161 }
4162
4163 // Handle [] indexing on String objects
4164 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004165 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4166 Handle<Object> result =
4167 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4168 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004169 }
4170
4171 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004172 return object->GetPrototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004173 }
4174
4175 return object->GetElement(index);
4176}
4177
4178
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004179MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4180 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004181 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004182 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004183
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004184 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004185 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004186 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004187 isolate->factory()->NewTypeError("non_object_property_load",
4188 HandleVector(args, 2));
4189 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190 }
4191
4192 // Check if the given key is an array index.
4193 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004194 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004195 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004196 }
4197
4198 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004199 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004200 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004201 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004202 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004203 bool has_pending_exception = false;
4204 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004205 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004206 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004207 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004208 }
4209
ager@chromium.org32912102009-01-16 10:38:43 +00004210 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004211 // the element if so.
4212 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004213 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004214 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004215 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004216 }
4217}
4218
4219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004220RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004221 NoHandleAllocation ha;
4222 ASSERT(args.length() == 2);
4223
4224 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004225 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004226
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004227 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004228}
4229
4230
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004231// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004232RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004233 NoHandleAllocation ha;
4234 ASSERT(args.length() == 2);
4235
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004236 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004237 // itself.
4238 //
4239 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004240 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004241 // global proxy object never has properties. This is the case
4242 // because the global proxy object forwards everything to its hidden
4243 // prototype including local lookups.
4244 //
4245 // Additionally, we need to make sure that we do not cache results
4246 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004247 if (args[0]->IsJSObject()) {
4248 if (!args[0]->IsJSGlobalProxy() &&
4249 !args[0]->IsAccessCheckNeeded() &&
4250 args[1]->IsString()) {
4251 JSObject* receiver = JSObject::cast(args[0]);
4252 String* key = String::cast(args[1]);
4253 if (receiver->HasFastProperties()) {
4254 // Attempt to use lookup cache.
4255 Map* receiver_map = receiver->map();
4256 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4257 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4258 if (offset != -1) {
4259 Object* value = receiver->FastPropertyAt(offset);
4260 return value->IsTheHole()
4261 ? isolate->heap()->undefined_value()
4262 : value;
4263 }
4264 // Lookup cache miss. Perform lookup and update the cache if
4265 // appropriate.
4266 LookupResult result(isolate);
4267 receiver->LocalLookup(key, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004268 if (result.IsFound() && result.type() == FIELD) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004269 int offset = result.GetFieldIndex();
4270 keyed_lookup_cache->Update(receiver_map, key, offset);
4271 return receiver->FastPropertyAt(offset);
4272 }
4273 } else {
4274 // Attempt dictionary lookup.
4275 StringDictionary* dictionary = receiver->property_dictionary();
4276 int entry = dictionary->FindEntry(key);
4277 if ((entry != StringDictionary::kNotFound) &&
4278 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4279 Object* value = dictionary->ValueAt(entry);
4280 if (!receiver->IsGlobalObject()) return value;
4281 value = JSGlobalPropertyCell::cast(value)->value();
4282 if (!value->IsTheHole()) return value;
4283 // If value is the hole do the general lookup.
4284 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004285 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004286 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4287 // JSObject without a string key. If the key is a Smi, check for a
4288 // definite out-of-bounds access to elements, which is a strong indicator
4289 // that subsequent accesses will also call the runtime. Proactively
4290 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4291 // doubles for those future calls in the case that the elements would
4292 // become FAST_DOUBLE_ELEMENTS.
4293 Handle<JSObject> js_object(args.at<JSObject>(0));
4294 ElementsKind elements_kind = js_object->GetElementsKind();
4295 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4296 elements_kind == FAST_DOUBLE_ELEMENTS) {
4297 FixedArrayBase* elements = js_object->elements();
4298 if (args.at<Smi>(1)->value() >= elements->length()) {
4299 MaybeObject* maybe_object = TransitionElements(js_object,
4300 FAST_ELEMENTS,
4301 isolate);
4302 if (maybe_object->IsFailure()) return maybe_object;
4303 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004304 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004305 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004306 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4307 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004308 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004309 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004310 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004311 if (index >= 0 && index < str->length()) {
4312 Handle<Object> result = GetCharAt(str, index);
4313 return *result;
4314 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004315 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004316
4317 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004318 return Runtime::GetObjectProperty(isolate,
4319 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004320 args.at<Object>(1));
4321}
4322
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004323
4324static bool IsValidAccessor(Handle<Object> obj) {
4325 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
4326}
4327
4328
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004329// Implements part of 8.12.9 DefineOwnProperty.
4330// There are 3 cases that lead here:
4331// Step 4b - define a new accessor property.
4332// Steps 9c & 12 - replace an existing data property with an accessor property.
4333// Step 12 - update an existing accessor property with an accessor or generic
4334// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004335RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004336 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004337 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004338 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004339 RUNTIME_ASSERT(!obj->IsNull());
4340 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
4341 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
4342 RUNTIME_ASSERT(IsValidAccessor(getter));
4343 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
4344 RUNTIME_ASSERT(IsValidAccessor(setter));
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004345 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
ager@chromium.org5c838252010-02-19 08:53:10 +00004346 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004347 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004348
danno@chromium.org88aa0582012-03-23 15:11:57 +00004349 bool fast = obj->HasFastProperties();
4350 JSObject::DefineAccessor(obj, name, getter, setter, attr);
4351 if (fast) JSObject::TransformToFastProperties(obj, 0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004352 return isolate->heap()->undefined_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00004353}
4354
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004355// Implements part of 8.12.9 DefineOwnProperty.
4356// There are 3 cases that lead here:
4357// Step 4a - define a new data property.
4358// Steps 9b & 12 - replace an existing accessor property with a data property.
4359// Step 12 - update an existing data property with a data or generic
4360// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004361RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004362 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004363 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004364 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
4365 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004366 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004367 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
ager@chromium.org5c838252010-02-19 08:53:10 +00004368 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004369 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4370
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004371 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004372 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004373
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004374 // Special case for callback properties.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004375 if (result.IsFound() && result.type() == CALLBACKS) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004376 Object* callback = result.GetCallbackObject();
4377 // To be compatible with Safari we do not change the value on API objects
4378 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4379 // the value.
4380 if (callback->IsAccessorInfo()) {
4381 return isolate->heap()->undefined_value();
4382 }
4383 // Avoid redefining foreign callback as data property, just use the stored
4384 // setter to update the value instead.
4385 // TODO(mstarzinger): So far this only works if property attributes don't
4386 // change, this should be fixed once we cleanup the underlying code.
4387 if (callback->IsForeign() && result.GetAttributes() == attr) {
4388 return js_object->SetPropertyWithCallback(callback,
4389 *name,
4390 *obj_value,
4391 result.holder(),
4392 kStrictMode);
4393 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004394 }
4395
ager@chromium.org5c838252010-02-19 08:53:10 +00004396 // Take special care when attributes are different and there is already
4397 // a property. For simplicity we normalize the property which enables us
4398 // to not worry about changing the instance_descriptor and creating a new
4399 // map. The current version of SetObjectProperty does not handle attributes
4400 // correctly in the case where a property is a field and is reset with
4401 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004402 if (result.IsProperty() &&
4403 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004404 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004405 if (js_object->IsJSGlobalProxy()) {
4406 // Since the result is a property, the prototype will exist so
4407 // we don't have to check for null.
4408 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004409 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004410 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004411 // Use IgnoreAttributes version since a readonly property may be
4412 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004413 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4414 *obj_value,
4415 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004416 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004417
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004418 return Runtime::ForceSetObjectProperty(isolate,
4419 js_object,
4420 name,
4421 obj_value,
4422 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004423}
4424
4425
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004426MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4427 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004428 Handle<Object> key,
4429 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004430 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004431 StrictModeFlag strict_mode) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004432 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004433 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004434
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004435 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004436 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004437 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004438 isolate->factory()->NewTypeError("non_object_property_store",
4439 HandleVector(args, 2));
4440 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004441 }
4442
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004443 if (object->IsJSProxy()) {
4444 bool has_pending_exception = false;
4445 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4446 if (has_pending_exception) return Failure::Exception();
4447 return JSProxy::cast(*object)->SetProperty(
4448 String::cast(*name), *value, attr, strict_mode);
4449 }
4450
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004451 // If the object isn't a JavaScript object, we ignore the store.
4452 if (!object->IsJSObject()) return *value;
4453
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004454 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4455
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004456 // Check if the given key is an array index.
4457 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004458 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004459 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4460 // of a string using [] notation. We need to support this too in
4461 // JavaScript.
4462 // In the case of a String object we just need to redirect the assignment to
4463 // the underlying string if the index is in range. Since the underlying
4464 // string does nothing with the assignment then we can ignore such
4465 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004466 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004467 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004468 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004469
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004470 Handle<Object> result = JSObject::SetElement(
4471 js_object, index, value, attr, strict_mode, set_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004472 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004473 return *value;
4474 }
4475
4476 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004477 Handle<Object> result;
4478 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004479 result = JSObject::SetElement(
4480 js_object, index, value, attr, strict_mode, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004481 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004482 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004483 key_string->TryFlatten();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004484 result = JSReceiver::SetProperty(
4485 js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004486 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004487 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004488 return *value;
4489 }
4490
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004491 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004492 bool has_pending_exception = false;
4493 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4494 if (has_pending_exception) return Failure::Exception();
4495 Handle<String> name = Handle<String>::cast(converted);
4496
4497 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004498 return js_object->SetElement(
4499 index, *value, attr, strict_mode, true, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004500 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004501 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004502 }
4503}
4504
4505
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004506MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4507 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004508 Handle<Object> key,
4509 Handle<Object> value,
4510 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004511 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004512
4513 // Check if the given key is an array index.
4514 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004515 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004516 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4517 // of a string using [] notation. We need to support this too in
4518 // JavaScript.
4519 // In the case of a String object we just need to redirect the assignment to
4520 // the underlying string if the index is in range. Since the underlying
4521 // string does nothing with the assignment then we can ignore such
4522 // assignments.
4523 if (js_object->IsStringObjectWithCharacterAt(index)) {
4524 return *value;
4525 }
4526
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004527 return js_object->SetElement(
4528 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004529 }
4530
4531 if (key->IsString()) {
4532 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004533 return js_object->SetElement(
4534 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004535 } else {
4536 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004537 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004538 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4539 *value,
4540 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004541 }
4542 }
4543
4544 // Call-back into JavaScript to convert the key to a string.
4545 bool has_pending_exception = false;
4546 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4547 if (has_pending_exception) return Failure::Exception();
4548 Handle<String> name = Handle<String>::cast(converted);
4549
4550 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004551 return js_object->SetElement(
4552 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004553 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004554 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004555 }
4556}
4557
4558
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004559MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004560 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004561 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004562 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004563
4564 // Check if the given key is an array index.
4565 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004566 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004567 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4568 // characters of a string using [] notation. In the case of a
4569 // String object we just need to redirect the deletion to the
4570 // underlying string if the index is in range. Since the
4571 // underlying string does nothing with the deletion, we can ignore
4572 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004573 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004574 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004575 }
4576
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004577 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004578 }
4579
4580 Handle<String> key_string;
4581 if (key->IsString()) {
4582 key_string = Handle<String>::cast(key);
4583 } else {
4584 // Call-back into JavaScript to convert the key to a string.
4585 bool has_pending_exception = false;
4586 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4587 if (has_pending_exception) return Failure::Exception();
4588 key_string = Handle<String>::cast(converted);
4589 }
4590
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004591 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004592 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004593}
4594
4595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004596RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004597 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004598 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004599
4600 Handle<Object> object = args.at<Object>(0);
4601 Handle<Object> key = args.at<Object>(1);
4602 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004603 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004604 RUNTIME_ASSERT(
4605 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004606 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004607 PropertyAttributes attributes =
4608 static_cast<PropertyAttributes>(unchecked_attributes);
4609
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004610 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004611 if (args.length() == 5) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004612 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004613 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004614 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004615
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004616 return Runtime::SetObjectProperty(isolate,
4617 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004618 key,
4619 value,
4620 attributes,
4621 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004622}
4623
4624
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004625RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4626 NoHandleAllocation ha;
4627 RUNTIME_ASSERT(args.length() == 1);
4628 Handle<Object> object = args.at<Object>(0);
4629 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4630}
4631
4632
4633RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4634 NoHandleAllocation ha;
4635 RUNTIME_ASSERT(args.length() == 1);
4636 Handle<Object> object = args.at<Object>(0);
4637 return TransitionElements(object, FAST_ELEMENTS, isolate);
4638}
4639
4640
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004641// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004642// This is used to decide if we should transform null and undefined
4643// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004644RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004645 NoHandleAllocation ha;
4646 RUNTIME_ASSERT(args.length() == 1);
4647
4648 Handle<Object> object = args.at<Object>(0);
4649
4650 if (object->IsJSFunction()) {
4651 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004652 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004653 }
4654 return isolate->heap()->undefined_value();
4655}
4656
4657
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004658RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4659 RUNTIME_ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004660 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004661 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4662 Handle<Object> value = args.at<Object>(2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004663 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004664 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4665 HandleScope scope;
4666
4667 Object* raw_boilerplate_object = literals->get(literal_index);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004668 Handle<JSArray> boilerplate(JSArray::cast(raw_boilerplate_object));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004669#if DEBUG
4670 ElementsKind elements_kind = object->GetElementsKind();
4671#endif
4672 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4673 // Smis should never trigger transitions.
4674 ASSERT(!value->IsSmi());
4675
4676 if (value->IsNumber()) {
4677 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004678 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004679 if (IsMoreGeneralElementsKindTransition(boilerplate->GetElementsKind(),
4680 FAST_DOUBLE_ELEMENTS)) {
4681 JSObject::TransitionElementsKind(boilerplate, FAST_DOUBLE_ELEMENTS);
4682 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004683 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004684 FixedDoubleArray* double_array = FixedDoubleArray::cast(object->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004685 HeapNumber* number = HeapNumber::cast(*value);
4686 double_array->set(store_index, number->Number());
4687 } else {
4688 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4689 elements_kind == FAST_DOUBLE_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004690 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00004691 if (IsMoreGeneralElementsKindTransition(boilerplate->GetElementsKind(),
4692 FAST_ELEMENTS)) {
4693 JSObject::TransitionElementsKind(boilerplate, FAST_ELEMENTS);
4694 }
4695 FixedArray* object_array = FixedArray::cast(object->elements());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004696 object_array->set(store_index, *value);
4697 }
4698 return *object;
4699}
4700
4701
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00004702// Check whether debugger and is about to step into the callback that is passed
4703// to a built-in function such as Array.forEach.
4704RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugCallbackSupportsStepping) {
4705 if (!isolate->IsDebuggerActive()) return isolate->heap()->false_value();
4706 CONVERT_ARG_CHECKED(Object, callback, 0);
4707 // We do not step into the callback if it's a builtin or not even a function.
4708 if (!callback->IsJSFunction() || JSFunction::cast(callback)->IsBuiltin()) {
4709 return isolate->heap()->false_value();
4710 }
4711 return isolate->heap()->true_value();
4712}
4713
4714
4715// Set one shot breakpoints for the callback function that is passed to a
4716// built-in function such as Array.forEach to enable stepping into the callback.
4717RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrepareStepInIfStepping) {
4718 Debug* debug = isolate->debug();
4719 if (!debug->IsStepping()) return NULL;
4720 CONVERT_ARG_CHECKED(Object, callback, 0);
4721 HandleScope scope(isolate);
4722 Handle<SharedFunctionInfo> shared_info(JSFunction::cast(callback)->shared());
4723 // When leaving the callback, step out has been activated, but not performed
4724 // if we do not leave the builtin. To be able to step into the callback
4725 // again, we need to clear the step out at this point.
4726 debug->ClearStepOut();
4727 debug->FloodWithOneShot(shared_info);
4728 return NULL;
4729}
4730
4731
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004732// Set a local property, even if it is READ_ONLY. If the property does not
4733// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004734RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004735 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004736 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004737 CONVERT_ARG_CHECKED(JSObject, object, 0);
4738 CONVERT_ARG_CHECKED(String, name, 1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004739 // Compute attributes.
4740 PropertyAttributes attributes = NONE;
4741 if (args.length() == 4) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004742 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004743 // Only attribute bits should be set.
4744 RUNTIME_ASSERT(
4745 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4746 attributes = static_cast<PropertyAttributes>(unchecked_value);
4747 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004748
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004749 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004750 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004751}
4752
4753
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004754RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004755 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004756 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004757
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004758 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4759 CONVERT_ARG_CHECKED(String, key, 1);
4760 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004761 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004762 ? JSReceiver::STRICT_DELETION
4763 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004764}
4765
4766
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004767static Object* HasLocalPropertyImplementation(Isolate* isolate,
4768 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004769 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004770 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004771 // Handle hidden prototypes. If there's a hidden prototype above this thing
4772 // then we have to check it for properties, because they are supposed to
4773 // look like they are on this object.
4774 Handle<Object> proto(object->GetPrototype());
4775 if (proto->IsJSObject() &&
4776 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004777 return HasLocalPropertyImplementation(isolate,
4778 Handle<JSObject>::cast(proto),
4779 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004780 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004781 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004782}
4783
4784
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004785RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004786 NoHandleAllocation ha;
4787 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004788 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004789
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004790 uint32_t index;
4791 const bool key_is_array_index = key->AsArrayIndex(&index);
4792
ager@chromium.org9085a012009-05-11 19:22:57 +00004793 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004794 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004795 if (obj->IsJSObject()) {
4796 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004797 // Fast case: either the key is a real named property or it is not
4798 // an array index and there are no interceptors or hidden
4799 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004800 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004801 Map* map = object->map();
4802 if (!key_is_array_index &&
4803 !map->has_named_interceptor() &&
4804 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4805 return isolate->heap()->false_value();
4806 }
4807 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004808 HandleScope scope(isolate);
4809 return HasLocalPropertyImplementation(isolate,
4810 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004811 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004812 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004813 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004814 String* string = String::cast(obj);
4815 if (index < static_cast<uint32_t>(string->length())) {
4816 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004817 }
4818 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004819 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004820}
4821
4822
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004823RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004824 NoHandleAllocation na;
4825 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004826 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4827 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004828
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004829 bool result = receiver->HasProperty(key);
4830 if (isolate->has_pending_exception()) return Failure::Exception();
4831 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004832}
4833
4834
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004835RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004836 NoHandleAllocation na;
4837 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004838 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4839 CONVERT_SMI_ARG_CHECKED(index, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004840
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004841 bool result = receiver->HasElement(index);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004842 if (isolate->has_pending_exception()) return Failure::Exception();
4843 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004844}
4845
4846
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004847RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004848 NoHandleAllocation ha;
4849 ASSERT(args.length() == 2);
4850
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004851 CONVERT_ARG_CHECKED(JSObject, object, 0);
4852 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004853
4854 uint32_t index;
4855 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004856 JSObject::LocalElementType type = object->HasLocalElement(index);
4857 switch (type) {
4858 case JSObject::UNDEFINED_ELEMENT:
4859 case JSObject::STRING_CHARACTER_ELEMENT:
4860 return isolate->heap()->false_value();
4861 case JSObject::INTERCEPTED_ELEMENT:
4862 case JSObject::FAST_ELEMENT:
4863 return isolate->heap()->true_value();
4864 case JSObject::DICTIONARY_ELEMENT: {
4865 if (object->IsJSGlobalProxy()) {
4866 Object* proto = object->GetPrototype();
4867 if (proto->IsNull()) {
4868 return isolate->heap()->false_value();
4869 }
4870 ASSERT(proto->IsJSGlobalObject());
4871 object = JSObject::cast(proto);
4872 }
4873 FixedArray* elements = FixedArray::cast(object->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004874 SeededNumberDictionary* dictionary = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004875 if (elements->map() ==
4876 isolate->heap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004877 dictionary = SeededNumberDictionary::cast(elements->get(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004878 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004879 dictionary = SeededNumberDictionary::cast(elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004880 }
4881 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004882 ASSERT(entry != SeededNumberDictionary::kNotFound);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004883 PropertyDetails details = dictionary->DetailsAt(entry);
4884 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4885 }
4886 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004887 }
4888
ager@chromium.org870a0b62008-11-04 11:43:05 +00004889 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004890 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004891}
4892
4893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004894RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004895 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004896 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004897 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004898 bool threw = false;
4899 Handle<JSArray> result = GetKeysFor(object, &threw);
4900 if (threw) return Failure::Exception();
4901 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004902}
4903
4904
4905// Returns either a FixedArray as Runtime_GetPropertyNames,
4906// or, if the given object has an enum cache that contains
4907// all enumerable properties of the object and its prototypes
4908// have none, the map of the object. This is used to speed up
4909// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004910RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004911 ASSERT(args.length() == 1);
4912
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004913 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004914
4915 if (raw_object->IsSimpleEnum()) return raw_object->map();
4916
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004917 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004918 Handle<JSReceiver> object(raw_object);
4919 bool threw = false;
4920 Handle<FixedArray> content =
4921 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4922 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004923
4924 // Test again, since cache may have been built by preceding call.
4925 if (object->IsSimpleEnum()) return object->map();
4926
4927 return *content;
4928}
4929
4930
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004931// Find the length of the prototype chain that is to to handled as one. If a
4932// prototype object is hidden it is to be viewed as part of the the object it
4933// is prototype for.
4934static int LocalPrototypeChainLength(JSObject* obj) {
4935 int count = 1;
4936 Object* proto = obj->GetPrototype();
4937 while (proto->IsJSObject() &&
4938 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4939 count++;
4940 proto = JSObject::cast(proto)->GetPrototype();
4941 }
4942 return count;
4943}
4944
4945
4946// Return the names of the local named properties.
4947// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004948RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004949 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004950 ASSERT(args.length() == 1);
4951 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004952 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004953 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004954 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004955
4956 // Skip the global proxy as it has no properties and always delegates to the
4957 // real global object.
4958 if (obj->IsJSGlobalProxy()) {
4959 // Only collect names if access is permitted.
4960 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004961 !isolate->MayNamedAccess(*obj,
4962 isolate->heap()->undefined_value(),
4963 v8::ACCESS_KEYS)) {
4964 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4965 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004966 }
4967 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4968 }
4969
4970 // Find the number of objects making up this.
4971 int length = LocalPrototypeChainLength(*obj);
4972
4973 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004974 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004975 int total_property_count = 0;
4976 Handle<JSObject> jsproto = obj;
4977 for (int i = 0; i < length; i++) {
4978 // Only collect names if access is permitted.
4979 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004980 !isolate->MayNamedAccess(*jsproto,
4981 isolate->heap()->undefined_value(),
4982 v8::ACCESS_KEYS)) {
4983 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4984 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004985 }
4986 int n;
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00004987 n = jsproto->NumberOfLocalProperties();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004988 local_property_count[i] = n;
4989 total_property_count += n;
4990 if (i < length - 1) {
4991 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4992 }
4993 }
4994
4995 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004996 Handle<FixedArray> names =
4997 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004998
4999 // Get the property names.
5000 jsproto = obj;
5001 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005002 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005003 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005004 jsproto->GetLocalPropertyNames(*names, next_copy_index);
5005 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00005006 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005007 proto_with_hidden_properties++;
5008 }
5009 if (i < length - 1) {
5010 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5011 }
5012 }
5013
5014 // Filter out name of hidden propeties object.
5015 if (proto_with_hidden_properties > 0) {
5016 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005017 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005018 names->length() - proto_with_hidden_properties);
5019 int dest_pos = 0;
5020 for (int i = 0; i < total_property_count; i++) {
5021 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005022 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005023 continue;
5024 }
5025 names->set(dest_pos++, name);
5026 }
5027 }
5028
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005029 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005030}
5031
5032
5033// Return the names of the local indexed properties.
5034// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005035RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005036 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005037 ASSERT(args.length() == 1);
5038 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005039 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005040 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005041 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005042
5043 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005044 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005045 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005046 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005047}
5048
5049
5050// Return information on whether an object has a named or indexed interceptor.
5051// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005052RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005053 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005054 ASSERT(args.length() == 1);
5055 if (!args[0]->IsJSObject()) {
5056 return Smi::FromInt(0);
5057 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005058 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005059
5060 int result = 0;
5061 if (obj->HasNamedInterceptor()) result |= 2;
5062 if (obj->HasIndexedInterceptor()) result |= 1;
5063
5064 return Smi::FromInt(result);
5065}
5066
5067
5068// Return property names from named interceptor.
5069// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005070RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005071 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005072 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005073 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005074
5075 if (obj->HasNamedInterceptor()) {
5076 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5077 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5078 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005079 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005080}
5081
5082
5083// Return element names from indexed interceptor.
5084// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005085RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005086 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005087 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005088 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005089
5090 if (obj->HasIndexedInterceptor()) {
5091 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5092 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5093 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005094 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005095}
5096
5097
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005098RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005099 ASSERT_EQ(args.length(), 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005100 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005101 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005102 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005103
5104 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005105 // Do access checks before going to the global object.
5106 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005107 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005108 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005109 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5110 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005111 }
5112
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005113 Handle<Object> proto(object->GetPrototype());
5114 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005115 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005116 object = Handle<JSObject>::cast(proto);
5117 }
5118
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005119 bool threw = false;
5120 Handle<FixedArray> contents =
5121 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5122 if (threw) return Failure::Exception();
5123
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005124 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5125 // property array and since the result is mutable we have to create
5126 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005127 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005128 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005129 for (int i = 0; i < length; i++) {
5130 Object* entry = contents->get(i);
5131 if (entry->IsString()) {
5132 copy->set(i, entry);
5133 } else {
5134 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005135 HandleScope scope(isolate);
5136 Handle<Object> entry_handle(entry, isolate);
5137 Handle<Object> entry_str =
5138 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005139 copy->set(i, *entry_str);
5140 }
5141 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005142 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005143}
5144
5145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005146RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005147 NoHandleAllocation ha;
5148 ASSERT(args.length() == 1);
5149
5150 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005151 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005152 it.AdvanceToArgumentsFrame();
5153 JavaScriptFrame* frame = it.frame();
5154
5155 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005156 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005157
5158 // Try to convert the key to an index. If successful and within
5159 // index return the the argument from the frame.
5160 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005161 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005162 return frame->GetParameter(index);
5163 }
5164
5165 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005166 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005167 bool exception = false;
5168 Handle<Object> converted =
5169 Execution::ToString(args.at<Object>(0), &exception);
5170 if (exception) return Failure::Exception();
5171 Handle<String> key = Handle<String>::cast(converted);
5172
5173 // Try to convert the string key into an array index.
5174 if (key->AsArrayIndex(&index)) {
5175 if (index < n) {
5176 return frame->GetParameter(index);
5177 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005178 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005179 }
5180 }
5181
5182 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005183 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5184 if (key->Equals(isolate->heap()->callee_symbol())) {
5185 Object* function = frame->function();
5186 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005187 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005188 return isolate->Throw(*isolate->factory()->NewTypeError(
5189 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5190 }
5191 return function;
5192 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005193
5194 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005195 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005196}
5197
5198
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005199RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005200 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005201 Object* object = args[0];
5202 return (object->IsJSObject() && !object->IsGlobalObject())
5203 ? JSObject::cast(object)->TransformToFastProperties(0)
5204 : object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005205}
5206
5207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005208RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005209 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005210 Object* obj = args[0];
5211 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5212 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5213 : obj;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005214}
5215
5216
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005217RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005218 NoHandleAllocation ha;
5219 ASSERT(args.length() == 1);
5220
5221 return args[0]->ToBoolean();
5222}
5223
5224
5225// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5226// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005227RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005228 NoHandleAllocation ha;
5229
5230 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005231 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005232 HeapObject* heap_obj = HeapObject::cast(obj);
5233
5234 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005235 if (heap_obj->map()->is_undetectable()) {
5236 return isolate->heap()->undefined_symbol();
5237 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005238
5239 InstanceType instance_type = heap_obj->map()->instance_type();
5240 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005241 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005242 }
5243
5244 switch (instance_type) {
5245 case ODDBALL_TYPE:
5246 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005247 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005248 }
5249 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005250 return FLAG_harmony_typeof
5251 ? isolate->heap()->null_symbol()
5252 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005253 }
5254 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005255 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005256 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005257 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005258 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005259 default:
5260 // For any kind of object not handled above, the spec rule for
5261 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005262 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005263 }
5264}
5265
5266
lrn@chromium.org25156de2010-04-06 13:10:27 +00005267static bool AreDigits(const char*s, int from, int to) {
5268 for (int i = from; i < to; i++) {
5269 if (s[i] < '0' || s[i] > '9') return false;
5270 }
5271
5272 return true;
5273}
5274
5275
5276static int ParseDecimalInteger(const char*s, int from, int to) {
5277 ASSERT(to - from < 10); // Overflow is not possible.
5278 ASSERT(from < to);
5279 int d = s[from] - '0';
5280
5281 for (int i = from + 1; i < to; i++) {
5282 d = 10 * d + (s[i] - '0');
5283 }
5284
5285 return d;
5286}
5287
5288
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005289RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005290 NoHandleAllocation ha;
5291 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005292 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005293 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005294
5295 // Fast case: short integer or some sorts of junk values.
5296 int len = subject->length();
5297 if (subject->IsSeqAsciiString()) {
5298 if (len == 0) return Smi::FromInt(0);
5299
5300 char const* data = SeqAsciiString::cast(subject)->GetChars();
5301 bool minus = (data[0] == '-');
5302 int start_pos = (minus ? 1 : 0);
5303
5304 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005305 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005306 } else if (data[start_pos] > '9') {
5307 // Fast check for a junk value. A valid string may start from a
5308 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5309 // the 'I' character ('Infinity'). All of that have codes not greater than
5310 // '9' except 'I'.
5311 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005312 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005313 }
5314 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5315 // The maximal/minimal smi has 10 digits. If the string has less digits we
5316 // know it will fit into the smi-data type.
5317 int d = ParseDecimalInteger(data, start_pos, len);
5318 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005319 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005320 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005321 } else if (!subject->HasHashCode() &&
5322 len <= String::kMaxArrayIndexSize &&
5323 (len == 1 || data[0] != '0')) {
5324 // String hash is not calculated yet but all the data are present.
5325 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005326 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005327#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005328 subject->Hash(); // Force hash calculation.
5329 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5330 static_cast<int>(hash));
5331#endif
5332 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005333 }
5334 return Smi::FromInt(d);
5335 }
5336 }
5337
5338 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005339 return isolate->heap()->NumberFromDouble(
5340 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005341}
5342
5343
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005344RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005345 NoHandleAllocation ha;
5346 ASSERT(args.length() == 1);
5347
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005348 CONVERT_ARG_CHECKED(JSArray, codes, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005349 int length = Smi::cast(codes->length())->value();
5350
5351 // Check if the string can be ASCII.
5352 int i;
5353 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005354 Object* element;
5355 { MaybeObject* maybe_element = codes->GetElement(i);
5356 // We probably can't get an exception here, but just in order to enforce
5357 // the checking of inputs in the runtime calls we check here.
5358 if (!maybe_element->ToObject(&element)) return maybe_element;
5359 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005360 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5361 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5362 break;
5363 }
5364
lrn@chromium.org303ada72010-10-27 09:33:13 +00005365 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005366 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005367 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005368 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005369 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005370 }
5371
lrn@chromium.org303ada72010-10-27 09:33:13 +00005372 Object* object = NULL;
5373 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005374 String* result = String::cast(object);
5375 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005376 Object* element;
5377 { MaybeObject* maybe_element = codes->GetElement(i);
5378 if (!maybe_element->ToObject(&element)) return maybe_element;
5379 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005380 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005381 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005382 }
5383 return result;
5384}
5385
5386
5387// kNotEscaped is generated by the following:
5388//
5389// #!/bin/perl
5390// for (my $i = 0; $i < 256; $i++) {
5391// print "\n" if $i % 16 == 0;
5392// my $c = chr($i);
5393// my $escaped = 1;
5394// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5395// print $escaped ? "0, " : "1, ";
5396// }
5397
5398
5399static bool IsNotEscaped(uint16_t character) {
5400 // Only for 8 bit characters, the rest are always escaped (in a different way)
5401 ASSERT(character < 256);
5402 static const char kNotEscaped[256] = {
5403 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5404 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5405 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5406 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5407 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5408 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5409 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5410 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5411 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5412 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5413 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5414 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5415 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5416 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5417 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5418 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5419 };
5420 return kNotEscaped[character] != 0;
5421}
5422
5423
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005424RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005425 const char hex_chars[] = "0123456789ABCDEF";
5426 NoHandleAllocation ha;
5427 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005428 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005429
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005430 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005431
5432 int escaped_length = 0;
5433 int length = source->length();
5434 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005435 Access<StringInputBuffer> buffer(
5436 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005437 buffer->Reset(source);
5438 while (buffer->has_more()) {
5439 uint16_t character = buffer->GetNext();
5440 if (character >= 256) {
5441 escaped_length += 6;
5442 } else if (IsNotEscaped(character)) {
5443 escaped_length++;
5444 } else {
5445 escaped_length += 3;
5446 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005447 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005448 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005449 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005450 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005451 return Failure::OutOfMemoryException();
5452 }
5453 }
5454 }
5455 // No length change implies no change. Return original string if no change.
5456 if (escaped_length == length) {
5457 return source;
5458 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005459 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005460 { MaybeObject* maybe_o =
5461 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005462 if (!maybe_o->ToObject(&o)) return maybe_o;
5463 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005464 String* destination = String::cast(o);
5465 int dest_position = 0;
5466
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005467 Access<StringInputBuffer> buffer(
5468 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005469 buffer->Rewind();
5470 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005471 uint16_t chr = buffer->GetNext();
5472 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005473 destination->Set(dest_position, '%');
5474 destination->Set(dest_position+1, 'u');
5475 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5476 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5477 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5478 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005479 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005480 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005481 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005482 dest_position++;
5483 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005484 destination->Set(dest_position, '%');
5485 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5486 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005487 dest_position += 3;
5488 }
5489 }
5490 return destination;
5491}
5492
5493
5494static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5495 static const signed char kHexValue['g'] = {
5496 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5497 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5498 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5499 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5500 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5501 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5502 -1, 10, 11, 12, 13, 14, 15 };
5503
5504 if (character1 > 'f') return -1;
5505 int hi = kHexValue[character1];
5506 if (hi == -1) return -1;
5507 if (character2 > 'f') return -1;
5508 int lo = kHexValue[character2];
5509 if (lo == -1) return -1;
5510 return (hi << 4) + lo;
5511}
5512
5513
ager@chromium.org870a0b62008-11-04 11:43:05 +00005514static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005515 int i,
5516 int length,
5517 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005518 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005519 int32_t hi = 0;
5520 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005521 if (character == '%' &&
5522 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005523 source->Get(i + 1) == 'u' &&
5524 (hi = TwoDigitHex(source->Get(i + 2),
5525 source->Get(i + 3))) != -1 &&
5526 (lo = TwoDigitHex(source->Get(i + 4),
5527 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005528 *step = 6;
5529 return (hi << 8) + lo;
5530 } else if (character == '%' &&
5531 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005532 (lo = TwoDigitHex(source->Get(i + 1),
5533 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005534 *step = 3;
5535 return lo;
5536 } else {
5537 *step = 1;
5538 return character;
5539 }
5540}
5541
5542
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005543RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005544 NoHandleAllocation ha;
5545 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005546 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005547
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005548 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005549
5550 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005551 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005552
5553 int unescaped_length = 0;
5554 for (int i = 0; i < length; unescaped_length++) {
5555 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005556 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005557 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005558 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005559 i += step;
5560 }
5561
5562 // No length change implies no change. Return original string if no change.
5563 if (unescaped_length == length)
5564 return source;
5565
lrn@chromium.org303ada72010-10-27 09:33:13 +00005566 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005567 { MaybeObject* maybe_o =
5568 ascii ?
5569 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5570 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005571 if (!maybe_o->ToObject(&o)) return maybe_o;
5572 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005573 String* destination = String::cast(o);
5574
5575 int dest_position = 0;
5576 for (int i = 0; i < length; dest_position++) {
5577 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005578 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005579 i += step;
5580 }
5581 return destination;
5582}
5583
5584
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005585static const unsigned int kQuoteTableLength = 128u;
5586
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005587static const int kJsonQuotesCharactersPerEntry = 8;
5588static const char* const JsonQuotes =
5589 "\\u0000 \\u0001 \\u0002 \\u0003 "
5590 "\\u0004 \\u0005 \\u0006 \\u0007 "
5591 "\\b \\t \\n \\u000b "
5592 "\\f \\r \\u000e \\u000f "
5593 "\\u0010 \\u0011 \\u0012 \\u0013 "
5594 "\\u0014 \\u0015 \\u0016 \\u0017 "
5595 "\\u0018 \\u0019 \\u001a \\u001b "
5596 "\\u001c \\u001d \\u001e \\u001f "
5597 " ! \\\" # "
5598 "$ % & ' "
5599 "( ) * + "
5600 ", - . / "
5601 "0 1 2 3 "
5602 "4 5 6 7 "
5603 "8 9 : ; "
5604 "< = > ? "
5605 "@ A B C "
5606 "D E F G "
5607 "H I J K "
5608 "L M N O "
5609 "P Q R S "
5610 "T U V W "
5611 "X Y Z [ "
5612 "\\\\ ] ^ _ "
5613 "` a b c "
5614 "d e f g "
5615 "h i j k "
5616 "l m n o "
5617 "p q r s "
5618 "t u v w "
5619 "x y z { "
5620 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005621
5622
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005623// For a string that is less than 32k characters it should always be
5624// possible to allocate it in new space.
5625static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5626
5627
5628// Doing JSON quoting cannot make the string more than this many times larger.
5629static const int kJsonQuoteWorstCaseBlowup = 6;
5630
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005631static const int kSpaceForQuotesAndComma = 3;
5632static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005633
5634// Covers the entire ASCII range (all other characters are unchanged by JSON
5635// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005636static const byte JsonQuoteLengths[kQuoteTableLength] = {
5637 6, 6, 6, 6, 6, 6, 6, 6,
5638 2, 2, 2, 6, 2, 2, 6, 6,
5639 6, 6, 6, 6, 6, 6, 6, 6,
5640 6, 6, 6, 6, 6, 6, 6, 6,
5641 1, 1, 2, 1, 1, 1, 1, 1,
5642 1, 1, 1, 1, 1, 1, 1, 1,
5643 1, 1, 1, 1, 1, 1, 1, 1,
5644 1, 1, 1, 1, 1, 1, 1, 1,
5645 1, 1, 1, 1, 1, 1, 1, 1,
5646 1, 1, 1, 1, 1, 1, 1, 1,
5647 1, 1, 1, 1, 1, 1, 1, 1,
5648 1, 1, 1, 1, 2, 1, 1, 1,
5649 1, 1, 1, 1, 1, 1, 1, 1,
5650 1, 1, 1, 1, 1, 1, 1, 1,
5651 1, 1, 1, 1, 1, 1, 1, 1,
5652 1, 1, 1, 1, 1, 1, 1, 1,
5653};
5654
5655
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005656template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005657MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005658
5659
5660template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005661MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5662 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005663}
5664
5665
5666template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005667MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5668 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005669}
5670
5671
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005672template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005673static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5674 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005675 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005676 const Char* read_cursor = characters.start();
5677 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005678 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005679 int quoted_length = kSpaceForQuotes;
5680 while (read_cursor < end) {
5681 Char c = *(read_cursor++);
5682 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5683 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005684 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005685 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005686 }
5687 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005688 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5689 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005690 Object* new_object;
5691 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005692 return new_alloc;
5693 }
5694 StringType* new_string = StringType::cast(new_object);
5695
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005696 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005697 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005698 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005699 *(write_cursor++) = '"';
5700
5701 read_cursor = characters.start();
5702 while (read_cursor < end) {
5703 Char c = *(read_cursor++);
5704 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5705 *(write_cursor++) = c;
5706 } else {
5707 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5708 const char* replacement = JsonQuotes +
5709 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5710 for (int i = 0; i < len; i++) {
5711 *write_cursor++ = *replacement++;
5712 }
5713 }
5714 }
5715 *(write_cursor++) = '"';
5716 return new_string;
5717}
5718
5719
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005720template <typename SinkChar, typename SourceChar>
5721static inline SinkChar* WriteQuoteJsonString(
5722 Isolate* isolate,
5723 SinkChar* write_cursor,
5724 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005725 // SinkChar is only char if SourceChar is guaranteed to be char.
5726 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005727 const SourceChar* read_cursor = characters.start();
5728 const SourceChar* end = read_cursor + characters.length();
5729 *(write_cursor++) = '"';
5730 while (read_cursor < end) {
5731 SourceChar c = *(read_cursor++);
5732 if (sizeof(SourceChar) > 1u &&
5733 static_cast<unsigned>(c) >= kQuoteTableLength) {
5734 *(write_cursor++) = static_cast<SinkChar>(c);
5735 } else {
5736 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5737 const char* replacement = JsonQuotes +
5738 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5739 write_cursor[0] = replacement[0];
5740 if (len > 1) {
5741 write_cursor[1] = replacement[1];
5742 if (len > 2) {
5743 ASSERT(len == 6);
5744 write_cursor[2] = replacement[2];
5745 write_cursor[3] = replacement[3];
5746 write_cursor[4] = replacement[4];
5747 write_cursor[5] = replacement[5];
5748 }
5749 }
5750 write_cursor += len;
5751 }
5752 }
5753 *(write_cursor++) = '"';
5754 return write_cursor;
5755}
5756
5757
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005758template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005759static MaybeObject* QuoteJsonString(Isolate* isolate,
5760 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005761 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005762 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005763 int worst_case_length =
5764 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005765 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005766 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005767 }
5768
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005769 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5770 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005771 Object* new_object;
5772 if (!new_alloc->ToObject(&new_object)) {
5773 return new_alloc;
5774 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005775 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005776 // Even if our string is small enough to fit in new space we still have to
5777 // handle it being allocated in old space as may happen in the third
5778 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5779 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005780 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005781 }
5782 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005783 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005784
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005785 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005786 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005787 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005788 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5789 write_cursor,
5790 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005791 int final_length = static_cast<int>(
5792 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005793 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005794 isolate->heap()->new_space()->
5795 template ShrinkStringAtAllocationBoundary<StringType>(
5796 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005797 return new_string;
5798}
5799
5800
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005801RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005802 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005803 CONVERT_ARG_CHECKED(String, str, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005804 if (!str->IsFlat()) {
5805 MaybeObject* try_flatten = str->TryFlatten();
5806 Object* flat;
5807 if (!try_flatten->ToObject(&flat)) {
5808 return try_flatten;
5809 }
5810 str = String::cast(flat);
5811 ASSERT(str->IsFlat());
5812 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005813 String::FlatContent flat = str->GetFlatContent();
5814 ASSERT(flat.IsFlat());
5815 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005816 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005817 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005818 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005819 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005820 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005821 }
5822}
5823
5824
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005825RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005826 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005827 CONVERT_ARG_CHECKED(String, str, 0);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005828 if (!str->IsFlat()) {
5829 MaybeObject* try_flatten = str->TryFlatten();
5830 Object* flat;
5831 if (!try_flatten->ToObject(&flat)) {
5832 return try_flatten;
5833 }
5834 str = String::cast(flat);
5835 ASSERT(str->IsFlat());
5836 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005837 String::FlatContent flat = str->GetFlatContent();
5838 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005839 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005840 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005841 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005842 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005843 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005844 }
5845}
5846
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005847
5848template <typename Char, typename StringType>
5849static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5850 FixedArray* array,
5851 int worst_case_length) {
5852 int length = array->length();
5853
5854 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5855 worst_case_length);
5856 Object* new_object;
5857 if (!new_alloc->ToObject(&new_object)) {
5858 return new_alloc;
5859 }
5860 if (!isolate->heap()->new_space()->Contains(new_object)) {
5861 // Even if our string is small enough to fit in new space we still have to
5862 // handle it being allocated in old space as may happen in the third
5863 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5864 // CEntryStub::GenerateCore.
5865 return isolate->heap()->undefined_value();
5866 }
5867 AssertNoAllocation no_gc;
5868 StringType* new_string = StringType::cast(new_object);
5869 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5870
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005871 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005872 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005873 *(write_cursor++) = '[';
5874 for (int i = 0; i < length; i++) {
5875 if (i != 0) *(write_cursor++) = ',';
5876 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005877 String::FlatContent content = str->GetFlatContent();
5878 ASSERT(content.IsFlat());
5879 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005880 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5881 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005882 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005883 } else {
5884 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5885 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005886 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005887 }
5888 }
5889 *(write_cursor++) = ']';
5890
5891 int final_length = static_cast<int>(
5892 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005893 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005894 isolate->heap()->new_space()->
5895 template ShrinkStringAtAllocationBoundary<StringType>(
5896 new_string, final_length);
5897 return new_string;
5898}
5899
5900
5901RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5902 NoHandleAllocation ha;
5903 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005904 CONVERT_ARG_CHECKED(JSArray, array, 0);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005905
5906 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5907 FixedArray* elements = FixedArray::cast(array->elements());
5908 int n = elements->length();
5909 bool ascii = true;
5910 int total_length = 0;
5911
5912 for (int i = 0; i < n; i++) {
5913 Object* elt = elements->get(i);
5914 if (!elt->IsString()) return isolate->heap()->undefined_value();
5915 String* element = String::cast(elt);
5916 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5917 total_length += element->length();
5918 if (ascii && element->IsTwoByteRepresentation()) {
5919 ascii = false;
5920 }
5921 }
5922
5923 int worst_case_length =
5924 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5925 + total_length * kJsonQuoteWorstCaseBlowup;
5926
5927 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5928 return isolate->heap()->undefined_value();
5929 }
5930
5931 if (ascii) {
5932 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5933 elements,
5934 worst_case_length);
5935 } else {
5936 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5937 elements,
5938 worst_case_length);
5939 }
5940}
5941
5942
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005943RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005944 NoHandleAllocation ha;
5945
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005946 CONVERT_ARG_CHECKED(String, s, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005947 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005948
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005949 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005950
lrn@chromium.org25156de2010-04-06 13:10:27 +00005951 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005952 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005953 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005954}
5955
5956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005957RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005958 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005959 CONVERT_ARG_CHECKED(String, str, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005960
5961 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005962 double value = StringToDouble(isolate->unicode_cache(),
5963 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005964
5965 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005966 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005967}
5968
5969
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005970template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005971MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005972 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005973 String* s,
5974 int length,
5975 int input_string_length,
5976 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005977 // We try this twice, once with the assumption that the result is no longer
5978 // than the input and, if that assumption breaks, again with the exact
5979 // length. This may not be pretty, but it is nicer than what was here before
5980 // and I hereby claim my vaffel-is.
5981 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005982 // Allocate the resulting string.
5983 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00005984 // NOTE: This assumes that the upper/lower case of an ASCII
5985 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005986 // might break in the future if we implement more context and locale
5987 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005988 Object* o;
5989 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005990 ? isolate->heap()->AllocateRawAsciiString(length)
5991 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005992 if (!maybe_o->ToObject(&o)) return maybe_o;
5993 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005994 String* result = String::cast(o);
5995 bool has_changed_character = false;
5996
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005997 // Convert all characters to upper case, assuming that they will fit
5998 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005999 Access<StringInputBuffer> buffer(
6000 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006001 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006002 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006003 // We can assume that the string is not empty
6004 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006005 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006006 bool has_next = buffer->has_more();
6007 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006008 int char_length = mapping->get(current, next, chars);
6009 if (char_length == 0) {
6010 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006011 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006012 i++;
6013 } else if (char_length == 1) {
6014 // Common case: converting the letter resulted in one character.
6015 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006016 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006017 has_changed_character = true;
6018 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006019 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006020 // We've assumed that the result would be as long as the
6021 // input but here is a character that converts to several
6022 // characters. No matter, we calculate the exact length
6023 // of the result and try the whole thing again.
6024 //
6025 // Note that this leaves room for optimization. We could just
6026 // memcpy what we already have to the result string. Also,
6027 // the result string is the last object allocated we could
6028 // "realloc" it and probably, in the vast majority of cases,
6029 // extend the existing string to be able to hold the full
6030 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006031 int next_length = 0;
6032 if (has_next) {
6033 next_length = mapping->get(next, 0, chars);
6034 if (next_length == 0) next_length = 1;
6035 }
6036 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006037 while (buffer->has_more()) {
6038 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006039 // NOTE: we use 0 as the next character here because, while
6040 // the next character may affect what a character converts to,
6041 // it does not in any case affect the length of what it convert
6042 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006043 int char_length = mapping->get(current, 0, chars);
6044 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006045 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006046 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006047 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006048 return Failure::OutOfMemoryException();
6049 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006050 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006051 // Try again with the real length.
6052 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006053 } else {
6054 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006055 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006056 i++;
6057 }
6058 has_changed_character = true;
6059 }
6060 current = next;
6061 }
6062 if (has_changed_character) {
6063 return result;
6064 } else {
6065 // If we didn't actually change anything in doing the conversion
6066 // we simple return the result and let the converted string
6067 // become garbage; there is no reason to keep two identical strings
6068 // alive.
6069 return s;
6070 }
6071}
6072
6073
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006074namespace {
6075
lrn@chromium.org303ada72010-10-27 09:33:13 +00006076static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6077
6078
6079// Given a word and two range boundaries returns a word with high bit
6080// set in every byte iff the corresponding input byte was strictly in
6081// the range (m, n). All the other bits in the result are cleared.
6082// This function is only useful when it can be inlined and the
6083// boundaries are statically known.
6084// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006085// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006086static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006087 // Every byte in an ASCII string is less than or equal to 0x7F.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006088 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6089 // Use strict inequalities since in edge cases the function could be
6090 // further simplified.
6091 ASSERT(0 < m && m < n && n < 0x7F);
6092 // Has high bit set in every w byte less than n.
6093 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6094 // Has high bit set in every w byte greater than m.
6095 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6096 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6097}
6098
6099
6100enum AsciiCaseConversion {
6101 ASCII_TO_LOWER,
6102 ASCII_TO_UPPER
6103};
6104
6105
6106template <AsciiCaseConversion dir>
6107struct FastAsciiConverter {
6108 static bool Convert(char* dst, char* src, int length) {
6109#ifdef DEBUG
6110 char* saved_dst = dst;
6111 char* saved_src = src;
6112#endif
6113 // We rely on the distance between upper and lower case letters
6114 // being a known power of 2.
6115 ASSERT('a' - 'A' == (1 << 5));
6116 // Boundaries for the range of input characters than require conversion.
6117 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6118 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6119 bool changed = false;
6120 char* const limit = src + length;
6121#ifdef V8_HOST_CAN_READ_UNALIGNED
6122 // Process the prefix of the input that requires no conversion one
6123 // (machine) word at a time.
6124 while (src <= limit - sizeof(uintptr_t)) {
6125 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6126 if (AsciiRangeMask(w, lo, hi) != 0) {
6127 changed = true;
6128 break;
6129 }
6130 *reinterpret_cast<uintptr_t*>(dst) = w;
6131 src += sizeof(uintptr_t);
6132 dst += sizeof(uintptr_t);
6133 }
6134 // Process the remainder of the input performing conversion when
6135 // required one word at a time.
6136 while (src <= limit - sizeof(uintptr_t)) {
6137 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6138 uintptr_t m = AsciiRangeMask(w, lo, hi);
6139 // The mask has high (7th) bit set in every byte that needs
6140 // conversion and we know that the distance between cases is
6141 // 1 << 5.
6142 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6143 src += sizeof(uintptr_t);
6144 dst += sizeof(uintptr_t);
6145 }
6146#endif
6147 // Process the last few bytes of the input (or the whole input if
6148 // unaligned access is not supported).
6149 while (src < limit) {
6150 char c = *src;
6151 if (lo < c && c < hi) {
6152 c ^= (1 << 5);
6153 changed = true;
6154 }
6155 *dst = c;
6156 ++src;
6157 ++dst;
6158 }
6159#ifdef DEBUG
6160 CheckConvert(saved_dst, saved_src, length, changed);
6161#endif
6162 return changed;
6163 }
6164
6165#ifdef DEBUG
6166 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6167 bool expected_changed = false;
6168 for (int i = 0; i < length; i++) {
6169 if (dst[i] == src[i]) continue;
6170 expected_changed = true;
6171 if (dir == ASCII_TO_LOWER) {
6172 ASSERT('A' <= src[i] && src[i] <= 'Z');
6173 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6174 } else {
6175 ASSERT(dir == ASCII_TO_UPPER);
6176 ASSERT('a' <= src[i] && src[i] <= 'z');
6177 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6178 }
6179 }
6180 ASSERT(expected_changed == changed);
6181 }
6182#endif
6183};
6184
6185
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006186struct ToLowerTraits {
6187 typedef unibrow::ToLowercase UnibrowConverter;
6188
lrn@chromium.org303ada72010-10-27 09:33:13 +00006189 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006190};
6191
6192
6193struct ToUpperTraits {
6194 typedef unibrow::ToUppercase UnibrowConverter;
6195
lrn@chromium.org303ada72010-10-27 09:33:13 +00006196 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006197};
6198
6199} // namespace
6200
6201
6202template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006203MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006204 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006205 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006206 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006207 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006208 CONVERT_ARG_CHECKED(String, s, 0);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006209 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006210
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006211 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006212 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006213 if (length == 0) return s;
6214
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006215 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006216 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006217 // NOTE: This assumes that the upper/lower case of an ASCII
6218 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006219 // might break in the future if we implement more context and locale
6220 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006221 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006222 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006223 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006224 if (!maybe_o->ToObject(&o)) return maybe_o;
6225 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006226 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006227 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006228 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006229 return has_changed_character ? result : s;
6230 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006231
lrn@chromium.org303ada72010-10-27 09:33:13 +00006232 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006233 { MaybeObject* maybe_answer =
6234 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006235 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6236 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006237 if (answer->IsSmi()) {
6238 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006239 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006240 ConvertCaseHelper(isolate,
6241 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006242 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6243 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006244 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006245 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006246}
6247
6248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006249RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006250 return ConvertCase<ToLowerTraits>(
6251 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006252}
6253
6254
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006255RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006256 return ConvertCase<ToUpperTraits>(
6257 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006258}
6259
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006260
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006261static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006262 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006263}
6264
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006265
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006266RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006267 NoHandleAllocation ha;
6268 ASSERT(args.length() == 3);
6269
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006270 CONVERT_ARG_CHECKED(String, s, 0);
6271 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6272 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006273
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006274 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006275 int length = s->length();
6276
6277 int left = 0;
6278 if (trimLeft) {
6279 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6280 left++;
6281 }
6282 }
6283
6284 int right = length;
6285 if (trimRight) {
6286 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6287 right--;
6288 }
6289 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006290 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006291}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006292
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006293
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006294RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006295 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006296 HandleScope handle_scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006297 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6298 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006299 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6300
6301 int subject_length = subject->length();
6302 int pattern_length = pattern->length();
6303 RUNTIME_ASSERT(pattern_length > 0);
6304
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006305 if (limit == 0xffffffffu) {
6306 Handle<Object> cached_answer(StringSplitCache::Lookup(
6307 isolate->heap()->string_split_cache(),
6308 *subject,
6309 *pattern));
6310 if (*cached_answer != Smi::FromInt(0)) {
6311 Handle<JSArray> result =
6312 isolate->factory()->NewJSArrayWithElements(
6313 Handle<FixedArray>::cast(cached_answer));
6314 return *result;
6315 }
6316 }
6317
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006318 // The limit can be very large (0xffffffffu), but since the pattern
6319 // isn't empty, we can never create more parts than ~half the length
6320 // of the subject.
6321
6322 if (!subject->IsFlat()) FlattenString(subject);
6323
6324 static const int kMaxInitialListCapacity = 16;
6325
danno@chromium.org40cb8782011-05-25 07:58:50 +00006326 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006327
6328 // Find (up to limit) indices of separator and end-of-string in subject
6329 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6330 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006331 if (!pattern->IsFlat()) FlattenString(pattern);
6332
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006333 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006334
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006335 if (static_cast<uint32_t>(indices.length()) < limit) {
6336 indices.Add(subject_length);
6337 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006338
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006339 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006340
6341 // Create JSArray of substrings separated by separator.
6342 int part_count = indices.length();
6343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006344 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006345 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006346 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006347 result->set_length(Smi::FromInt(part_count));
6348
6349 ASSERT(result->HasFastElements());
6350
6351 if (part_count == 1 && indices.at(0) == subject_length) {
6352 FixedArray::cast(result->elements())->set(0, *subject);
6353 return *result;
6354 }
6355
6356 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6357 int part_start = 0;
6358 for (int i = 0; i < part_count; i++) {
6359 HandleScope local_loop_handle;
6360 int part_end = indices.at(i);
6361 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006362 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006363 elements->set(i, *substring);
6364 part_start = part_end + pattern_length;
6365 }
6366
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006367 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006368 if (result->HasFastElements()) {
6369 StringSplitCache::Enter(isolate->heap(),
6370 isolate->heap()->string_split_cache(),
6371 *subject,
6372 *pattern,
6373 *elements);
6374 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006375 }
6376
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006377 return *result;
6378}
6379
6380
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006381// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006382// one-char strings in the cache. Gives up on the first char that is
6383// not in the cache and fills the remainder with smi zeros. Returns
6384// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006385static int CopyCachedAsciiCharsToArray(Heap* heap,
6386 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006387 FixedArray* elements,
6388 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006389 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006390 FixedArray* ascii_cache = heap->single_character_string_cache();
6391 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006392 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006393 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006394 for (i = 0; i < length; ++i) {
6395 Object* value = ascii_cache->get(chars[i]);
6396 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006397 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006398 }
6399 if (i < length) {
6400 ASSERT(Smi::FromInt(0) == 0);
6401 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6402 }
6403#ifdef DEBUG
6404 for (int j = 0; j < length; ++j) {
6405 Object* element = elements->get(j);
6406 ASSERT(element == Smi::FromInt(0) ||
6407 (element->IsString() && String::cast(element)->LooksValid()));
6408 }
6409#endif
6410 return i;
6411}
6412
6413
6414// Converts a String to JSArray.
6415// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006416RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006417 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006418 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006419 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006420 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006421
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006422 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006423 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006424
6425 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006426 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006427 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006428 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006429 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006430 { MaybeObject* maybe_obj =
6431 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006432 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6433 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006434 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006435 String::FlatContent content = s->GetFlatContent();
6436 if (content.IsAscii()) {
6437 Vector<const char> chars = content.ToAsciiVector();
6438 // Note, this will initialize all elements (not only the prefix)
6439 // to prevent GC from seeing partially initialized array.
6440 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6441 chars.start(),
6442 *elements,
6443 length);
6444 } else {
6445 MemsetPointer(elements->data_start(),
6446 isolate->heap()->undefined_value(),
6447 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006448 }
6449 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006450 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006451 }
6452 for (int i = position; i < length; ++i) {
6453 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6454 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006455 }
6456
6457#ifdef DEBUG
6458 for (int i = 0; i < length; ++i) {
6459 ASSERT(String::cast(elements->get(i))->length() == 1);
6460 }
6461#endif
6462
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006463 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006464}
6465
6466
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006467RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006468 NoHandleAllocation ha;
6469 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006470 CONVERT_ARG_CHECKED(String, value, 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006471 return value->ToObject();
6472}
6473
6474
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006475bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006476 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006477 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006478 return char_length == 0;
6479}
6480
6481
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006482RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006483 NoHandleAllocation ha;
6484 ASSERT(args.length() == 1);
6485
6486 Object* number = args[0];
6487 RUNTIME_ASSERT(number->IsNumber());
6488
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006489 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006490}
6491
6492
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006493RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006494 NoHandleAllocation ha;
6495 ASSERT(args.length() == 1);
6496
6497 Object* number = args[0];
6498 RUNTIME_ASSERT(number->IsNumber());
6499
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006500 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006501}
6502
6503
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006504RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006505 NoHandleAllocation ha;
6506 ASSERT(args.length() == 1);
6507
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006508 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006509
6510 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6511 if (number > 0 && number <= Smi::kMaxValue) {
6512 return Smi::FromInt(static_cast<int>(number));
6513 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006514 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006515}
6516
6517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006518RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006519 NoHandleAllocation ha;
6520 ASSERT(args.length() == 1);
6521
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006522 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006523
6524 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6525 if (number > 0 && number <= Smi::kMaxValue) {
6526 return Smi::FromInt(static_cast<int>(number));
6527 }
6528
6529 double double_value = DoubleToInteger(number);
6530 // Map both -0 and +0 to +0.
6531 if (double_value == 0) double_value = 0;
6532
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006533 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006534}
6535
6536
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006537RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006538 NoHandleAllocation ha;
6539 ASSERT(args.length() == 1);
6540
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006541 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006542 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006543}
6544
6545
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006546RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006547 NoHandleAllocation ha;
6548 ASSERT(args.length() == 1);
6549
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006550 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006551
6552 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6553 if (number > 0 && number <= Smi::kMaxValue) {
6554 return Smi::FromInt(static_cast<int>(number));
6555 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006556 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006557}
6558
6559
ager@chromium.org870a0b62008-11-04 11:43:05 +00006560// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6561// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006562RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006563 NoHandleAllocation ha;
6564 ASSERT(args.length() == 1);
6565
6566 Object* obj = args[0];
6567 if (obj->IsSmi()) {
6568 return obj;
6569 }
6570 if (obj->IsHeapNumber()) {
6571 double value = HeapNumber::cast(obj)->value();
6572 int int_value = FastD2I(value);
6573 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6574 return Smi::FromInt(int_value);
6575 }
6576 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006577 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006578}
6579
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006580
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006581RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006582 NoHandleAllocation ha;
6583 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006584 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006585}
6586
6587
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006588RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006589 NoHandleAllocation ha;
6590 ASSERT(args.length() == 2);
6591
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006592 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6593 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006594 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006595}
6596
6597
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006598RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006599 NoHandleAllocation ha;
6600 ASSERT(args.length() == 2);
6601
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006602 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6603 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006604 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006605}
6606
6607
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006608RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006609 NoHandleAllocation ha;
6610 ASSERT(args.length() == 2);
6611
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006612 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6613 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006614 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006615}
6616
6617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006618RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006619 NoHandleAllocation ha;
6620 ASSERT(args.length() == 1);
6621
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006622 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006623 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006624}
6625
6626
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006627RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006628 NoHandleAllocation ha;
6629 ASSERT(args.length() == 0);
6630
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006631 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006632}
6633
6634
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006635RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006636 NoHandleAllocation ha;
6637 ASSERT(args.length() == 2);
6638
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006639 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6640 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006641 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006642}
6643
6644
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006645RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006646 NoHandleAllocation ha;
6647 ASSERT(args.length() == 2);
6648
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006649 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6650 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006651
ager@chromium.org3811b432009-10-28 14:53:37 +00006652 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006653 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006654 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006655}
6656
6657
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006658RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006659 NoHandleAllocation ha;
6660 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006661 CONVERT_ARG_CHECKED(String, str1, 0);
6662 CONVERT_ARG_CHECKED(String, str2, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006663 isolate->counters()->string_add_runtime()->Increment();
6664 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006665}
6666
6667
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006668template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006669static inline void StringBuilderConcatHelper(String* special,
6670 sinkchar* sink,
6671 FixedArray* fixed_array,
6672 int array_length) {
6673 int position = 0;
6674 for (int i = 0; i < array_length; i++) {
6675 Object* element = fixed_array->get(i);
6676 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006677 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006678 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006679 int pos;
6680 int len;
6681 if (encoded_slice > 0) {
6682 // Position and length encoded in one smi.
6683 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6684 len = StringBuilderSubstringLength::decode(encoded_slice);
6685 } else {
6686 // Position and length encoded in two smis.
6687 Object* obj = fixed_array->get(++i);
6688 ASSERT(obj->IsSmi());
6689 pos = Smi::cast(obj)->value();
6690 len = -encoded_slice;
6691 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006692 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006693 sink + position,
6694 pos,
6695 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006696 position += len;
6697 } else {
6698 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006699 int element_length = string->length();
6700 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006701 position += element_length;
6702 }
6703 }
6704}
6705
6706
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006707RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006708 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006709 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006710 CONVERT_ARG_CHECKED(JSArray, array, 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006711 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006712 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006713 return Failure::OutOfMemoryException();
6714 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006715 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006716 CONVERT_ARG_CHECKED(String, special, 2);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006717
6718 // This assumption is used by the slice encoding in one or two smis.
6719 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6720
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006721 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006722 if (maybe_result->IsFailure()) return maybe_result;
6723
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006724 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006725 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006726 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006727 }
6728 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006729 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006730 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006731 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006732
6733 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006734 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006735 } else if (array_length == 1) {
6736 Object* first = fixed_array->get(0);
6737 if (first->IsString()) return first;
6738 }
6739
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006740 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006741 int position = 0;
6742 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006743 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006744 Object* elt = fixed_array->get(i);
6745 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006746 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006747 int smi_value = Smi::cast(elt)->value();
6748 int pos;
6749 int len;
6750 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006751 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006752 pos = StringBuilderSubstringPosition::decode(smi_value);
6753 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006754 } else {
6755 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006756 len = -smi_value;
6757 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006758 i++;
6759 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006760 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006761 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006762 Object* next_smi = fixed_array->get(i);
6763 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006764 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006765 }
6766 pos = Smi::cast(next_smi)->value();
6767 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006768 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006769 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006770 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006771 ASSERT(pos >= 0);
6772 ASSERT(len >= 0);
6773 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006774 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006775 }
6776 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006777 } else if (elt->IsString()) {
6778 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006779 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006780 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006781 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006782 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006783 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006784 } else {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006785 ASSERT(!elt->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006786 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006787 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006788 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006789 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006790 return Failure::OutOfMemoryException();
6791 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006792 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006793 }
6794
6795 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006796 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006797
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006798 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006799 { MaybeObject* maybe_object =
6800 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006801 if (!maybe_object->ToObject(&object)) return maybe_object;
6802 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006803 SeqAsciiString* answer = SeqAsciiString::cast(object);
6804 StringBuilderConcatHelper(special,
6805 answer->GetChars(),
6806 fixed_array,
6807 array_length);
6808 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006809 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006810 { MaybeObject* maybe_object =
6811 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006812 if (!maybe_object->ToObject(&object)) return maybe_object;
6813 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006814 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6815 StringBuilderConcatHelper(special,
6816 answer->GetChars(),
6817 fixed_array,
6818 array_length);
6819 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006820 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006821}
6822
6823
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006824RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006825 NoHandleAllocation ha;
6826 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006827 CONVERT_ARG_CHECKED(JSArray, array, 0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006828 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006829 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006830 return Failure::OutOfMemoryException();
6831 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006832 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006833 CONVERT_ARG_CHECKED(String, separator, 2);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006834
6835 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006836 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006837 }
6838 FixedArray* fixed_array = FixedArray::cast(array->elements());
6839 if (fixed_array->length() < array_length) {
6840 array_length = fixed_array->length();
6841 }
6842
6843 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006844 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006845 } else if (array_length == 1) {
6846 Object* first = fixed_array->get(0);
6847 if (first->IsString()) return first;
6848 }
6849
6850 int separator_length = separator->length();
6851 int max_nof_separators =
6852 (String::kMaxLength + separator_length - 1) / separator_length;
6853 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006854 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006855 return Failure::OutOfMemoryException();
6856 }
6857 int length = (array_length - 1) * separator_length;
6858 for (int i = 0; i < array_length; i++) {
6859 Object* element_obj = fixed_array->get(i);
6860 if (!element_obj->IsString()) {
6861 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006862 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006863 }
6864 String* element = String::cast(element_obj);
6865 int increment = element->length();
6866 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006867 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006868 return Failure::OutOfMemoryException();
6869 }
6870 length += increment;
6871 }
6872
6873 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006874 { MaybeObject* maybe_object =
6875 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006876 if (!maybe_object->ToObject(&object)) return maybe_object;
6877 }
6878 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6879
6880 uc16* sink = answer->GetChars();
6881#ifdef DEBUG
6882 uc16* end = sink + length;
6883#endif
6884
6885 String* first = String::cast(fixed_array->get(0));
6886 int first_length = first->length();
6887 String::WriteToFlat(first, sink, 0, first_length);
6888 sink += first_length;
6889
6890 for (int i = 1; i < array_length; i++) {
6891 ASSERT(sink + separator_length <= end);
6892 String::WriteToFlat(separator, sink, 0, separator_length);
6893 sink += separator_length;
6894
6895 String* element = String::cast(fixed_array->get(i));
6896 int element_length = element->length();
6897 ASSERT(sink + element_length <= end);
6898 String::WriteToFlat(element, sink, 0, element_length);
6899 sink += element_length;
6900 }
6901 ASSERT(sink == end);
6902
6903 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6904 return answer;
6905}
6906
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006907template <typename Char>
6908static void JoinSparseArrayWithSeparator(FixedArray* elements,
6909 int elements_length,
6910 uint32_t array_length,
6911 String* separator,
6912 Vector<Char> buffer) {
6913 int previous_separator_position = 0;
6914 int separator_length = separator->length();
6915 int cursor = 0;
6916 for (int i = 0; i < elements_length; i += 2) {
6917 int position = NumberToInt32(elements->get(i));
6918 String* string = String::cast(elements->get(i + 1));
6919 int string_length = string->length();
6920 if (string->length() > 0) {
6921 while (previous_separator_position < position) {
6922 String::WriteToFlat<Char>(separator, &buffer[cursor],
6923 0, separator_length);
6924 cursor += separator_length;
6925 previous_separator_position++;
6926 }
6927 String::WriteToFlat<Char>(string, &buffer[cursor],
6928 0, string_length);
6929 cursor += string->length();
6930 }
6931 }
6932 if (separator_length > 0) {
6933 // Array length must be representable as a signed 32-bit number,
6934 // otherwise the total string length would have been too large.
6935 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6936 int last_array_index = static_cast<int>(array_length - 1);
6937 while (previous_separator_position < last_array_index) {
6938 String::WriteToFlat<Char>(separator, &buffer[cursor],
6939 0, separator_length);
6940 cursor += separator_length;
6941 previous_separator_position++;
6942 }
6943 }
6944 ASSERT(cursor <= buffer.length());
6945}
6946
6947
6948RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6949 NoHandleAllocation ha;
6950 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006951 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006952 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6953 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006954 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006955 CONVERT_ARG_CHECKED(String, separator, 2);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006956 // elements_array is fast-mode JSarray of alternating positions
6957 // (increasing order) and strings.
6958 // array_length is length of original array (used to add separators);
6959 // separator is string to put between elements. Assumed to be non-empty.
6960
6961 // Find total length of join result.
6962 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006963 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006964 int max_string_length;
6965 if (is_ascii) {
6966 max_string_length = SeqAsciiString::kMaxLength;
6967 } else {
6968 max_string_length = SeqTwoByteString::kMaxLength;
6969 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006970 bool overflow = false;
6971 CONVERT_NUMBER_CHECKED(int, elements_length,
6972 Int32, elements_array->length());
6973 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6974 FixedArray* elements = FixedArray::cast(elements_array->elements());
6975 for (int i = 0; i < elements_length; i += 2) {
6976 RUNTIME_ASSERT(elements->get(i)->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006977 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
6978 String* string = String::cast(elements->get(i + 1));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006979 int length = string->length();
6980 if (is_ascii && !string->IsAsciiRepresentation()) {
6981 is_ascii = false;
6982 max_string_length = SeqTwoByteString::kMaxLength;
6983 }
6984 if (length > max_string_length ||
6985 max_string_length - length < string_length) {
6986 overflow = true;
6987 break;
6988 }
6989 string_length += length;
6990 }
6991 int separator_length = separator->length();
6992 if (!overflow && separator_length > 0) {
6993 if (array_length <= 0x7fffffffu) {
6994 int separator_count = static_cast<int>(array_length) - 1;
6995 int remaining_length = max_string_length - string_length;
6996 if ((remaining_length / separator_length) >= separator_count) {
6997 string_length += separator_length * (array_length - 1);
6998 } else {
6999 // Not room for the separators within the maximal string length.
7000 overflow = true;
7001 }
7002 } else {
7003 // Nonempty separator and at least 2^31-1 separators necessary
7004 // means that the string is too large to create.
7005 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
7006 overflow = true;
7007 }
7008 }
7009 if (overflow) {
7010 // Throw OutOfMemory exception for creating too large a string.
7011 V8::FatalProcessOutOfMemory("Array join result too large.");
7012 }
7013
7014 if (is_ascii) {
7015 MaybeObject* result_allocation =
7016 isolate->heap()->AllocateRawAsciiString(string_length);
7017 if (result_allocation->IsFailure()) return result_allocation;
7018 SeqAsciiString* result_string =
7019 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
7020 JoinSparseArrayWithSeparator<char>(elements,
7021 elements_length,
7022 array_length,
7023 separator,
7024 Vector<char>(result_string->GetChars(),
7025 string_length));
7026 return result_string;
7027 } else {
7028 MaybeObject* result_allocation =
7029 isolate->heap()->AllocateRawTwoByteString(string_length);
7030 if (result_allocation->IsFailure()) return result_allocation;
7031 SeqTwoByteString* result_string =
7032 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7033 JoinSparseArrayWithSeparator<uc16>(elements,
7034 elements_length,
7035 array_length,
7036 separator,
7037 Vector<uc16>(result_string->GetChars(),
7038 string_length));
7039 return result_string;
7040 }
7041}
7042
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007044RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007045 NoHandleAllocation ha;
7046 ASSERT(args.length() == 2);
7047
7048 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7049 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007050 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007051}
7052
7053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007054RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007055 NoHandleAllocation ha;
7056 ASSERT(args.length() == 2);
7057
7058 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7059 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007060 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007061}
7062
7063
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007064RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007065 NoHandleAllocation ha;
7066 ASSERT(args.length() == 2);
7067
7068 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7069 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007070 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007071}
7072
7073
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007074RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007075 NoHandleAllocation ha;
7076 ASSERT(args.length() == 1);
7077
7078 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007079 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007080}
7081
7082
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007083RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007084 NoHandleAllocation ha;
7085 ASSERT(args.length() == 2);
7086
7087 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7088 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007089 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007090}
7091
7092
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007093RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007094 NoHandleAllocation ha;
7095 ASSERT(args.length() == 2);
7096
7097 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7098 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007099 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007100}
7101
7102
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007103RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007104 NoHandleAllocation ha;
7105 ASSERT(args.length() == 2);
7106
7107 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7108 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007109 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007110}
7111
7112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007113RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007114 NoHandleAllocation ha;
7115 ASSERT(args.length() == 2);
7116
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007117 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7118 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007119 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7120 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7121 if (x == y) return Smi::FromInt(EQUAL);
7122 Object* result;
7123 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7124 result = Smi::FromInt(EQUAL);
7125 } else {
7126 result = Smi::FromInt(NOT_EQUAL);
7127 }
7128 return result;
7129}
7130
7131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007132RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007133 NoHandleAllocation ha;
7134 ASSERT(args.length() == 2);
7135
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007136 CONVERT_ARG_CHECKED(String, x, 0);
7137 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007138
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007139 bool not_equal = !x->Equals(y);
7140 // This is slightly convoluted because the value that signifies
7141 // equality is 0 and inequality is 1 so we have to negate the result
7142 // from String::Equals.
7143 ASSERT(not_equal == 0 || not_equal == 1);
7144 STATIC_CHECK(EQUAL == 0);
7145 STATIC_CHECK(NOT_EQUAL == 1);
7146 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007147}
7148
7149
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007150RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007151 NoHandleAllocation ha;
7152 ASSERT(args.length() == 3);
7153
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007154 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7155 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007156 if (isnan(x) || isnan(y)) return args[2];
7157 if (x == y) return Smi::FromInt(EQUAL);
7158 if (isless(x, y)) return Smi::FromInt(LESS);
7159 return Smi::FromInt(GREATER);
7160}
7161
7162
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007163// Compare two Smis as if they were converted to strings and then
7164// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007165RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007166 NoHandleAllocation ha;
7167 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007168 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7169 CONVERT_SMI_ARG_CHECKED(y_value, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007170
7171 // If the integers are equal so are the string representations.
7172 if (x_value == y_value) return Smi::FromInt(EQUAL);
7173
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007174 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007175 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007176 if (x_value == 0 || y_value == 0)
7177 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007178
ager@chromium.org32912102009-01-16 10:38:43 +00007179 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007180 // smallest because the char code of '-' is less than the char code
7181 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007182
7183 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7184 // architectures using 32-bit Smis.
7185 uint32_t x_scaled = x_value;
7186 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007187 if (x_value < 0 || y_value < 0) {
7188 if (y_value >= 0) return Smi::FromInt(LESS);
7189 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007190 x_scaled = -x_value;
7191 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007192 }
7193
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007194 static const uint32_t kPowersOf10[] = {
7195 1, 10, 100, 1000, 10*1000, 100*1000,
7196 1000*1000, 10*1000*1000, 100*1000*1000,
7197 1000*1000*1000
7198 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007199
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007200 // If the integers have the same number of decimal digits they can be
7201 // compared directly as the numeric order is the same as the
7202 // lexicographic order. If one integer has fewer digits, it is scaled
7203 // by some power of 10 to have the same number of digits as the longer
7204 // integer. If the scaled integers are equal it means the shorter
7205 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007206
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007207 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7208 int x_log2 = IntegerLog2(x_scaled);
7209 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7210 x_log10 -= x_scaled < kPowersOf10[x_log10];
7211
7212 int y_log2 = IntegerLog2(y_scaled);
7213 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7214 y_log10 -= y_scaled < kPowersOf10[y_log10];
7215
7216 int tie = EQUAL;
7217
7218 if (x_log10 < y_log10) {
7219 // X has fewer digits. We would like to simply scale up X but that
7220 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7221 // be scaled up to 9_000_000_000. So we scale up by the next
7222 // smallest power and scale down Y to drop one digit. It is OK to
7223 // drop one digit from the longer integer since the final digit is
7224 // past the length of the shorter integer.
7225 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7226 y_scaled /= 10;
7227 tie = LESS;
7228 } else if (y_log10 < x_log10) {
7229 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7230 x_scaled /= 10;
7231 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007232 }
7233
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007234 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7235 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7236 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007237}
7238
7239
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007240static Object* StringInputBufferCompare(RuntimeState* state,
7241 String* x,
7242 String* y) {
7243 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7244 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007245 bufx.Reset(x);
7246 bufy.Reset(y);
7247 while (bufx.has_more() && bufy.has_more()) {
7248 int d = bufx.GetNext() - bufy.GetNext();
7249 if (d < 0) return Smi::FromInt(LESS);
7250 else if (d > 0) return Smi::FromInt(GREATER);
7251 }
7252
7253 // x is (non-trivial) prefix of y:
7254 if (bufy.has_more()) return Smi::FromInt(LESS);
7255 // y is prefix of x:
7256 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7257}
7258
7259
7260static Object* FlatStringCompare(String* x, String* y) {
7261 ASSERT(x->IsFlat());
7262 ASSERT(y->IsFlat());
7263 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7264 int prefix_length = x->length();
7265 if (y->length() < prefix_length) {
7266 prefix_length = y->length();
7267 equal_prefix_result = Smi::FromInt(GREATER);
7268 } else if (y->length() > prefix_length) {
7269 equal_prefix_result = Smi::FromInt(LESS);
7270 }
7271 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007272 String::FlatContent x_content = x->GetFlatContent();
7273 String::FlatContent y_content = y->GetFlatContent();
7274 if (x_content.IsAscii()) {
7275 Vector<const char> x_chars = x_content.ToAsciiVector();
7276 if (y_content.IsAscii()) {
7277 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007278 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007279 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007280 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007281 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7282 }
7283 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007284 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7285 if (y_content.IsAscii()) {
7286 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007287 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7288 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007289 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007290 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7291 }
7292 }
7293 Object* result;
7294 if (r == 0) {
7295 result = equal_prefix_result;
7296 } else {
7297 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7298 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007299 ASSERT(result ==
7300 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007301 return result;
7302}
7303
7304
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007305RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007306 NoHandleAllocation ha;
7307 ASSERT(args.length() == 2);
7308
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007309 CONVERT_ARG_CHECKED(String, x, 0);
7310 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007311
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007312 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007313
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007314 // A few fast case tests before we flatten.
7315 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007316 if (y->length() == 0) {
7317 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007318 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007319 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007320 return Smi::FromInt(LESS);
7321 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007322
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007323 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007324 if (d < 0) return Smi::FromInt(LESS);
7325 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007326
lrn@chromium.org303ada72010-10-27 09:33:13 +00007327 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007328 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007329 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7330 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007331 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007332 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7333 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007334
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007335 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007336 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007337}
7338
7339
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007340RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007341 NoHandleAllocation ha;
7342 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007343 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007344
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007345 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007346 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007347}
7348
7349
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007350RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007351 NoHandleAllocation ha;
7352 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007353 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007354
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007355 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007356 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007357}
7358
7359
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007360RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007361 NoHandleAllocation ha;
7362 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007363 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007364
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007365 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007366 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007367}
7368
7369
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007370static const double kPiDividedBy4 = 0.78539816339744830962;
7371
7372
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007373RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007374 NoHandleAllocation ha;
7375 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007376 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007377
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007378 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7379 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007380 double result;
7381 if (isinf(x) && isinf(y)) {
7382 // Make sure that the result in case of two infinite arguments
7383 // is a multiple of Pi / 4. The sign of the result is determined
7384 // by the first argument (x) and the sign of the second argument
7385 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007386 int multiplier = (x < 0) ? -1 : 1;
7387 if (y < 0) multiplier *= 3;
7388 result = multiplier * kPiDividedBy4;
7389 } else {
7390 result = atan2(x, y);
7391 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007392 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007393}
7394
7395
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007396RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007397 NoHandleAllocation ha;
7398 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007399 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007400
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007401 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007402 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007403}
7404
7405
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007406RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007407 NoHandleAllocation ha;
7408 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007409 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007410
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007411 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007412 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007413}
7414
7415
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007416RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007417 NoHandleAllocation ha;
7418 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007419 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007420
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007421 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007422 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007423}
7424
7425
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007426RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007427 NoHandleAllocation ha;
7428 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007429 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007430
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007431 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007432 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007433}
7434
7435
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007436RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007437 NoHandleAllocation ha;
7438 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007439 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007440
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007441 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007442 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007443}
7444
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007445// Slow version of Math.pow. We check for fast paths for special cases.
7446// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007447RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007448 NoHandleAllocation ha;
7449 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007450 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007451
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007452 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007453
7454 // If the second argument is a smi, it is much faster to call the
7455 // custom powi() function than the generic pow().
7456 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007457 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007458 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007459 }
7460
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007461 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007462 int y_int = static_cast<int>(y);
7463 double result;
7464 if (y == y_int) {
7465 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7466 } else if (y == 0.5) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007467 result = (isinf(x)) ? V8_INFINITY
7468 : fast_sqrt(x + 0.0); // Convert -0 to +0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007469 } else if (y == -0.5) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007470 result = (isinf(x)) ? 0
7471 : 1.0 / fast_sqrt(x + 0.0); // Convert -0 to +0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007472 } else {
7473 result = power_double_double(x, y);
7474 }
7475 if (isnan(result)) return isolate->heap()->nan_value();
7476 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007477}
7478
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007479// Fast version of Math.pow if we know that y is not an integer and y is not
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007480// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007481RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007482 NoHandleAllocation ha;
7483 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007484 isolate->counters()->math_pow()->Increment();
7485
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007486 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7487 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007488 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007489 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007490 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007491 double result = power_double_double(x, y);
7492 if (isnan(result)) return isolate->heap()->nan_value();
7493 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007494 }
7495}
7496
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007497
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007498RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007499 NoHandleAllocation ha;
7500 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007501 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007502
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007503 if (!args[0]->IsHeapNumber()) {
7504 // Must be smi. Return the argument unchanged for all the other types
7505 // to make fuzz-natives test happy.
7506 return args[0];
7507 }
7508
7509 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7510
7511 double value = number->value();
7512 int exponent = number->get_exponent();
7513 int sign = number->get_sign();
7514
danno@chromium.org160a7b02011-04-18 15:51:38 +00007515 if (exponent < -1) {
7516 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7517 if (sign) return isolate->heap()->minus_zero_value();
7518 return Smi::FromInt(0);
7519 }
7520
7521 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7522 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007523 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007524 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007525 return Smi::FromInt(static_cast<int>(value + 0.5));
7526 }
7527
7528 // If the magnitude is big enough, there's no place for fraction part. If we
7529 // try to add 0.5 to this number, 1.0 will be added instead.
7530 if (exponent >= 52) {
7531 return number;
7532 }
7533
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007534 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007535
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007536 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007537 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007538}
7539
7540
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007541RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007542 NoHandleAllocation ha;
7543 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007544 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007545
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007546 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007547 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007548}
7549
7550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007551RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007552 NoHandleAllocation ha;
7553 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007554 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007555
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007556 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007557 return isolate->heap()->AllocateHeapNumber(fast_sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007558}
7559
7560
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007561RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007562 NoHandleAllocation ha;
7563 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007564 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007565
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007566 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007567 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007568}
7569
7570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007571RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007572 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007573 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007574
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007575 CONVERT_SMI_ARG_CHECKED(year, 0);
7576 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007577
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007578 return Smi::FromInt(isolate->date_cache()->DaysFromYearMonth(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007579}
7580
7581
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007582RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) {
7583 HandleScope scope(isolate);
7584 ASSERT(args.length() == 3);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007585
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007586 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
7587 CONVERT_DOUBLE_ARG_CHECKED(time, 1);
7588 CONVERT_SMI_ARG_CHECKED(is_utc, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007589
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007590 DateCache* date_cache = isolate->date_cache();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007591
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007592 Object* value = NULL;
7593 bool is_value_nan = false;
7594 if (isnan(time)) {
7595 value = isolate->heap()->nan_value();
7596 is_value_nan = true;
7597 } else if (!is_utc &&
7598 (time < -DateCache::kMaxTimeBeforeUTCInMs ||
7599 time > DateCache::kMaxTimeBeforeUTCInMs)) {
7600 value = isolate->heap()->nan_value();
7601 is_value_nan = true;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007602 } else {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007603 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
7604 if (time < -DateCache::kMaxTimeInMs ||
7605 time > DateCache::kMaxTimeInMs) {
7606 value = isolate->heap()->nan_value();
7607 is_value_nan = true;
7608 } else {
7609 MaybeObject* maybe_result =
7610 isolate->heap()->AllocateHeapNumber(DoubleToInteger(time));
7611 if (!maybe_result->ToObject(&value)) return maybe_result;
7612 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007613 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007614 date->SetValue(value, is_value_nan);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00007615 return value;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007616}
7617
7618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007619RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007620 HandleScope scope(isolate);
7621 ASSERT(args.length() == 3);
7622
7623 Handle<JSFunction> callee = args.at<JSFunction>(0);
7624 Object** parameters = reinterpret_cast<Object**>(args[1]);
7625 const int argument_count = Smi::cast(args[2])->value();
7626
7627 Handle<JSObject> result =
7628 isolate->factory()->NewArgumentsObject(callee, argument_count);
7629 // Allocate the elements if needed.
7630 int parameter_count = callee->shared()->formal_parameter_count();
7631 if (argument_count > 0) {
7632 if (parameter_count > 0) {
7633 int mapped_count = Min(argument_count, parameter_count);
7634 Handle<FixedArray> parameter_map =
7635 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7636 parameter_map->set_map(
7637 isolate->heap()->non_strict_arguments_elements_map());
7638
7639 Handle<Map> old_map(result->map());
7640 Handle<Map> new_map =
7641 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007642 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007643
7644 result->set_map(*new_map);
7645 result->set_elements(*parameter_map);
7646
7647 // Store the context and the arguments array at the beginning of the
7648 // parameter map.
7649 Handle<Context> context(isolate->context());
7650 Handle<FixedArray> arguments =
7651 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7652 parameter_map->set(0, *context);
7653 parameter_map->set(1, *arguments);
7654
7655 // Loop over the actual parameters backwards.
7656 int index = argument_count - 1;
7657 while (index >= mapped_count) {
7658 // These go directly in the arguments array and have no
7659 // corresponding slot in the parameter map.
7660 arguments->set(index, *(parameters - index - 1));
7661 --index;
7662 }
7663
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007664 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007665 while (index >= 0) {
7666 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007667 Handle<String> name(scope_info->ParameterName(index));
7668 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007669 bool duplicate = false;
7670 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007671 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007672 duplicate = true;
7673 break;
7674 }
7675 }
7676
7677 if (duplicate) {
7678 // This goes directly in the arguments array with a hole in the
7679 // parameter map.
7680 arguments->set(index, *(parameters - index - 1));
7681 parameter_map->set_the_hole(index + 2);
7682 } else {
7683 // The context index goes in the parameter map with a hole in the
7684 // arguments array.
7685 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007686 for (int j = 0; j < context_local_count; ++j) {
7687 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007688 context_index = j;
7689 break;
7690 }
7691 }
7692 ASSERT(context_index >= 0);
7693 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007694 parameter_map->set(index + 2, Smi::FromInt(
7695 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007696 }
7697
7698 --index;
7699 }
7700 } else {
7701 // If there is no aliasing, the arguments object elements are not
7702 // special in any way.
7703 Handle<FixedArray> elements =
7704 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7705 result->set_elements(*elements);
7706 for (int i = 0; i < argument_count; ++i) {
7707 elements->set(i, *(parameters - i - 1));
7708 }
7709 }
7710 }
7711 return *result;
7712}
7713
7714
7715RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007716 NoHandleAllocation ha;
7717 ASSERT(args.length() == 3);
7718
7719 JSFunction* callee = JSFunction::cast(args[0]);
7720 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007721 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007722
lrn@chromium.org303ada72010-10-27 09:33:13 +00007723 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007724 { MaybeObject* maybe_result =
7725 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007726 if (!maybe_result->ToObject(&result)) return maybe_result;
7727 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007728 // Allocate the elements if needed.
7729 if (length > 0) {
7730 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007731 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007732 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007733 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7734 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007735
7736 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007737 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007738 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007739 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007740
7741 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007742 for (int i = 0; i < length; i++) {
7743 array->set(i, *--parameters, mode);
7744 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007745 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007746 }
7747 return result;
7748}
7749
7750
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007751RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007752 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007753 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007754 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
7755 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
7756 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007757
whesse@chromium.org7b260152011-06-20 15:33:18 +00007758 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007759 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007760 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007761 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007762 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7763 context,
7764 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007765 return *result;
7766}
7767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007768
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007769// Find the arguments of the JavaScript function invocation that called
7770// into C++ code. Collect these in a newly allocated array of handles (possibly
7771// prefixed by a number of empty handles).
7772static SmartArrayPointer<Handle<Object> > GetCallerArguments(
7773 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007774 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007775 // Find frame containing arguments passed to the caller.
7776 JavaScriptFrameIterator it;
7777 JavaScriptFrame* frame = it.frame();
7778 List<JSFunction*> functions(2);
7779 frame->GetFunctions(&functions);
7780 if (functions.length() > 1) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007781 int inlined_jsframe_index = functions.length() - 1;
7782 JSFunction* inlined_function = functions[inlined_jsframe_index];
7783 Vector<SlotRef> args_slots =
7784 SlotRef::ComputeSlotMappingForArguments(
7785 frame,
7786 inlined_jsframe_index,
7787 inlined_function->shared()->formal_parameter_count());
7788
7789 int args_count = args_slots.length();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007790
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007791 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007792 SmartArrayPointer<Handle<Object> > param_data(
7793 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007794 for (int i = 0; i < args_count; i++) {
7795 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007796 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007797 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007798
7799 args_slots.Dispose();
7800
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007801 return param_data;
7802 } else {
7803 it.AdvanceToArgumentsFrame();
7804 frame = it.frame();
7805 int args_count = frame->ComputeParametersCount();
7806
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007807 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007808 SmartArrayPointer<Handle<Object> > param_data(
7809 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007810 for (int i = 0; i < args_count; i++) {
7811 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007812 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007813 }
7814 return param_data;
7815 }
7816}
7817
7818
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007819RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
7820 HandleScope scope(isolate);
7821 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007822 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007823 RUNTIME_ASSERT(args[3]->IsNumber());
7824 Handle<Object> bindee = args.at<Object>(1);
7825
7826 // TODO(lrn): Create bound function in C++ code from premade shared info.
7827 bound_function->shared()->set_bound(true);
7828 // Get all arguments of calling function (Function.prototype.bind).
7829 int argc = 0;
7830 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
7831 // Don't count the this-arg.
7832 if (argc > 0) {
7833 ASSERT(*arguments[0] == args[2]);
7834 argc--;
7835 } else {
7836 ASSERT(args[2]->IsUndefined());
7837 }
7838 // Initialize array of bindings (function, this, and any existing arguments
7839 // if the function was already bound).
7840 Handle<FixedArray> new_bindings;
7841 int i;
7842 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
7843 Handle<FixedArray> old_bindings(
7844 JSFunction::cast(*bindee)->function_bindings());
7845 new_bindings =
7846 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
7847 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
7848 i = 0;
7849 for (int n = old_bindings->length(); i < n; i++) {
7850 new_bindings->set(i, old_bindings->get(i));
7851 }
7852 } else {
7853 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
7854 new_bindings = isolate->factory()->NewFixedArray(array_size);
7855 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
7856 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
7857 i = 2;
7858 }
7859 // Copy arguments, skipping the first which is "this_arg".
7860 for (int j = 0; j < argc; j++, i++) {
7861 new_bindings->set(i, *arguments[j + 1]);
7862 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007863 new_bindings->set_map_no_write_barrier(
7864 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007865 bound_function->set_function_bindings(*new_bindings);
7866
7867 // Update length.
7868 Handle<String> length_symbol = isolate->factory()->length_symbol();
7869 Handle<Object> new_length(args.at<Object>(3));
7870 PropertyAttributes attr =
7871 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
7872 ForceSetProperty(bound_function, length_symbol, new_length, attr);
7873 return *bound_function;
7874}
7875
7876
7877RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
7878 HandleScope handles(isolate);
7879 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007880 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007881 if (callable->IsJSFunction()) {
7882 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
7883 if (function->shared()->bound()) {
7884 Handle<FixedArray> bindings(function->function_bindings());
7885 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
7886 return *isolate->factory()->NewJSArrayWithElements(bindings);
7887 }
7888 }
7889 return isolate->heap()->undefined_value();
7890}
7891
7892
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007893RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007894 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007895 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007896 // First argument is a function to use as a constructor.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007897 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007898 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007899
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007900 // The argument is a bound function. Extract its bound arguments
7901 // and callable.
7902 Handle<FixedArray> bound_args =
7903 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
7904 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
7905 Handle<Object> bound_function(
7906 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
7907 ASSERT(!bound_function->IsJSFunction() ||
7908 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007909
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007910 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007911 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007912 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007913 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007914 param_data[i] = Handle<Object>(bound_args->get(
7915 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007916 }
7917
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007918 if (!bound_function->IsJSFunction()) {
7919 bool exception_thrown;
7920 bound_function = Execution::TryGetConstructorDelegate(bound_function,
7921 &exception_thrown);
7922 if (exception_thrown) return Failure::Exception();
7923 }
7924 ASSERT(bound_function->IsJSFunction());
7925
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007926 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007927 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007928 Execution::New(Handle<JSFunction>::cast(bound_function),
7929 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007930 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007931 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007932 }
7933 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007934 return *result;
7935}
7936
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007937
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007938static void TrySettingInlineConstructStub(Isolate* isolate,
7939 Handle<JSFunction> function) {
7940 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007941 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007942 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007943 }
7944 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007945 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007946 Handle<Code> code = compiler.CompileConstructStub(function);
7947 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007948 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007949}
7950
7951
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007952RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007953 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007954 ASSERT(args.length() == 1);
7955
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007956 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007957
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007958 // If the constructor isn't a proper function we throw a type error.
7959 if (!constructor->IsJSFunction()) {
7960 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7961 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007962 isolate->factory()->NewTypeError("not_constructor", arguments);
7963 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007964 }
7965
7966 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007967
7968 // If function should not have prototype, construction is not allowed. In this
7969 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007970 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007971 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7972 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007973 isolate->factory()->NewTypeError("not_constructor", arguments);
7974 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007975 }
7976
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007977#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007978 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007979 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007980 if (debug->StepInActive()) {
7981 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007982 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007983#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007984
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007985 if (function->has_initial_map()) {
7986 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007987 // The 'Function' function ignores the receiver object when
7988 // called using 'new' and creates a new JSFunction object that
7989 // is returned. The receiver object is only used for error
7990 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007991 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007992 // allocate JSFunctions since it does not properly initialize
7993 // the shared part of the function. Since the receiver is
7994 // ignored anyway, we use the global object as the receiver
7995 // instead of a new JSFunction object. This way, errors are
7996 // reported the same way whether or not 'Function' is called
7997 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007998 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007999 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008000 }
8001
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008002 // The function should be compiled for the optimization hints to be
8003 // available. We cannot use EnsureCompiled because that forces a
8004 // compilation through the shared function info which makes it
8005 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008006 if (!function->is_compiled()) {
8007 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8008 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008009
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008010 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008011 if (!function->has_initial_map() &&
8012 shared->IsInobjectSlackTrackingInProgress()) {
8013 // The tracking is already in progress for another function. We can only
8014 // track one initial_map at a time, so we force the completion before the
8015 // function is called as a constructor for the first time.
8016 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008017 }
8018
8019 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008020 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8021 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008022 // Delay setting the stub if inobject slack tracking is in progress.
8023 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008024 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008025 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008026
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008027 isolate->counters()->constructed_objects()->Increment();
8028 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008029
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008030 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008031}
8032
8033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008034RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008035 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008036 ASSERT(args.length() == 1);
8037
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008038 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008039 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008040 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008041
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008042 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008043}
8044
8045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008046RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008047 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008048 ASSERT(args.length() == 1);
8049
8050 Handle<JSFunction> function = args.at<JSFunction>(0);
8051#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008052 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008053 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008054 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008055 PrintF("]\n");
8056 }
8057#endif
8058
lrn@chromium.org34e60782011-09-15 07:25:40 +00008059 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008060 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008061 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008062 return Failure::Exception();
8063 }
8064
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008065 // All done. Return the compiled code.
8066 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008067 return function->code();
8068}
8069
8070
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008071RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008072 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008073 ASSERT(args.length() == 1);
8074 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008075
8076 // If the function is not compiled ignore the lazy
8077 // recompilation. This can happen if the debugger is activated and
8078 // the function is returned to the not compiled state.
8079 if (!function->shared()->is_compiled()) {
8080 function->ReplaceCode(function->shared()->code());
8081 return function->code();
8082 }
8083
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008084 // If the function is not optimizable or debugger is active continue using the
8085 // code from the full compiler.
8086 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008087 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008088 if (FLAG_trace_opt) {
8089 PrintF("[failed to optimize ");
8090 function->PrintName();
8091 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8092 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008093 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008094 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008095 function->ReplaceCode(function->shared()->code());
8096 return function->code();
8097 }
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00008098 function->shared()->code()->set_profiler_ticks(0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008099 if (JSFunction::CompileOptimized(function,
8100 AstNode::kNoNumber,
8101 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008102 return function->code();
8103 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008104 if (FLAG_trace_opt) {
8105 PrintF("[failed to optimize ");
8106 function->PrintName();
8107 PrintF(": optimized compilation failed]\n");
8108 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008109 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008110 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008111}
8112
8113
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008114class ActivationsFinder : public ThreadVisitor {
8115 public:
8116 explicit ActivationsFinder(JSFunction* function)
8117 : function_(function), has_activations_(false) {}
8118
8119 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8120 if (has_activations_) return;
8121
8122 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8123 JavaScriptFrame* frame = it.frame();
8124 if (frame->is_optimized() && frame->function() == function_) {
8125 has_activations_ = true;
8126 return;
8127 }
8128 }
8129 }
8130
8131 bool has_activations() { return has_activations_; }
8132
8133 private:
8134 JSFunction* function_;
8135 bool has_activations_;
8136};
8137
8138
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008139static void MaterializeArgumentsObjectInFrame(Isolate* isolate,
8140 JavaScriptFrame* frame) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008141 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008142 Handle<Object> arguments;
8143 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008144 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008145 if (arguments.is_null()) {
8146 // FunctionGetArguments can't throw an exception, so cast away the
8147 // doubt with an assert.
8148 arguments = Handle<Object>(
8149 Accessors::FunctionGetArguments(*function,
8150 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008151 ASSERT(*arguments != isolate->heap()->null_value());
8152 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008153 }
8154 frame->SetExpression(i, *arguments);
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00008155 if (FLAG_trace_deopt) {
8156 PrintF("Materializing arguments object for frame %p - %p: %p ",
8157 reinterpret_cast<void*>(frame->sp()),
8158 reinterpret_cast<void*>(frame->fp()),
8159 reinterpret_cast<void*>(*arguments));
8160 arguments->ShortPrint();
8161 PrintF("\n");
8162 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008163 }
8164 }
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008165}
8166
8167
8168RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
8169 HandleScope scope(isolate);
8170 ASSERT(args.length() == 1);
8171 RUNTIME_ASSERT(args[0]->IsSmi());
8172 Deoptimizer::BailoutType type =
8173 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
8174 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8175 ASSERT(isolate->heap()->IsAllocationAllowed());
8176 int jsframes = deoptimizer->jsframe_count();
8177
8178 deoptimizer->MaterializeHeapNumbers();
8179 delete deoptimizer;
8180
8181 JavaScriptFrameIterator it(isolate);
8182 for (int i = 0; i < jsframes - 1; i++) {
8183 MaterializeArgumentsObjectInFrame(isolate, it.frame());
8184 it.Advance();
8185 }
8186
8187 JavaScriptFrame* frame = it.frame();
8188 RUNTIME_ASSERT(frame->function()->IsJSFunction());
8189 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
8190 MaterializeArgumentsObjectInFrame(isolate, frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008191
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008192 if (type == Deoptimizer::EAGER) {
8193 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008194 }
8195
8196 // Avoid doing too much work when running with --always-opt and keep
8197 // the optimized code around.
8198 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008199 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008200 }
8201
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008202 // Find other optimized activations of the function.
8203 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008204 while (!it.done()) {
8205 JavaScriptFrame* frame = it.frame();
8206 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008207 has_other_activations = true;
8208 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008209 }
8210 it.Advance();
8211 }
8212
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008213 if (!has_other_activations) {
8214 ActivationsFinder activations_finder(*function);
8215 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8216 has_other_activations = activations_finder.has_activations();
8217 }
8218
8219 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008220 if (FLAG_trace_deopt) {
8221 PrintF("[removing optimized code for: ");
8222 function->PrintName();
8223 PrintF("]\n");
8224 }
8225 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008226 } else {
8227 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008228 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008229 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008230}
8231
8232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008233RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008234 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008235 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008236 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008237}
8238
8239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008240RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008241 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008242 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008243 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008244 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008245
8246 Deoptimizer::DeoptimizeFunction(*function);
8247
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008248 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008249}
8250
8251
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008252RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8253#if defined(USE_SIMULATOR)
8254 return isolate->heap()->true_value();
8255#else
8256 return isolate->heap()->false_value();
8257#endif
8258}
8259
8260
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008261RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8262 HandleScope scope(isolate);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008263 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008264 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008265
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008266 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8267 function->MarkForLazyRecompilation();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008268
8269 Code* unoptimized = function->shared()->code();
8270 if (args.length() == 2 &&
8271 unoptimized->kind() == Code::FUNCTION) {
8272 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
8273 CHECK(type->IsEqualTo(CStrVector("osr")));
8274 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
8275 unoptimized->set_allow_osr_at_loop_nesting_level(
8276 Code::kMaxLoopNestingMarker);
8277 }
8278
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008279 return isolate->heap()->undefined_value();
8280}
8281
8282
lrn@chromium.org1c092762011-05-09 09:42:16 +00008283RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8284 HandleScope scope(isolate);
8285 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008286 // The least significant bit (after untagging) indicates whether the
8287 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008288 if (!V8::UseCrankshaft()) {
8289 return Smi::FromInt(4); // 4 == "never".
8290 }
8291 if (FLAG_always_opt) {
8292 return Smi::FromInt(3); // 3 == "always".
8293 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008294 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008295 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8296 : Smi::FromInt(2); // 2 == "no".
8297}
8298
8299
8300RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8301 HandleScope scope(isolate);
8302 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008303 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008304 return Smi::FromInt(function->shared()->opt_count());
8305}
8306
8307
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008308RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008309 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008310 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008311 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008312
8313 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008314 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008315
8316 // We have hit a back edge in an unoptimized frame for a function that was
8317 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008318 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008319 // Keep track of whether we've succeeded in optimizing.
8320 bool succeeded = unoptimized->optimizable();
8321 if (succeeded) {
8322 // If we are trying to do OSR when there are already optimized
8323 // activations of the function, it means (a) the function is directly or
8324 // indirectly recursive and (b) an optimized invocation has been
8325 // deoptimized so that we are currently in an unoptimized activation.
8326 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008327 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008328 while (succeeded && !it.done()) {
8329 JavaScriptFrame* frame = it.frame();
8330 succeeded = !frame->is_optimized() || frame->function() != *function;
8331 it.Advance();
8332 }
8333 }
8334
8335 int ast_id = AstNode::kNoNumber;
8336 if (succeeded) {
8337 // The top JS function is this one, the PC is somewhere in the
8338 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008339 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008340 JavaScriptFrame* frame = it.frame();
8341 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008342 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008343 ASSERT(unoptimized->contains(frame->pc()));
8344
8345 // Use linear search of the unoptimized code's stack check table to find
8346 // the AST id matching the PC.
8347 Address start = unoptimized->instruction_start();
8348 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008349 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008350 uint32_t table_length = Memory::uint32_at(table_cursor);
8351 table_cursor += kIntSize;
8352 for (unsigned i = 0; i < table_length; ++i) {
8353 // Table entries are (AST id, pc offset) pairs.
8354 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8355 if (pc_offset == target_pc_offset) {
8356 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8357 break;
8358 }
8359 table_cursor += 2 * kIntSize;
8360 }
8361 ASSERT(ast_id != AstNode::kNoNumber);
8362 if (FLAG_trace_osr) {
8363 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8364 function->PrintName();
8365 PrintF("]\n");
8366 }
8367
8368 // Try to compile the optimized code. A true return value from
8369 // CompileOptimized means that compilation succeeded, not necessarily
8370 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008371 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008372 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008373 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8374 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008375 if (data->OsrPcOffset()->value() >= 0) {
8376 if (FLAG_trace_osr) {
8377 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008378 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008379 }
8380 ASSERT(data->OsrAstId()->value() == ast_id);
8381 } else {
8382 // We may never generate the desired OSR entry if we emit an
8383 // early deoptimize.
8384 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008385 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008386 } else {
8387 succeeded = false;
8388 }
8389 }
8390
8391 // Revert to the original stack checks in the original unoptimized code.
8392 if (FLAG_trace_osr) {
8393 PrintF("[restoring original stack checks in ");
8394 function->PrintName();
8395 PrintF("]\n");
8396 }
yangguo@chromium.org56454712012-02-16 15:33:53 +00008397 Handle<Code> check_code;
yangguo@chromium.org56454712012-02-16 15:33:53 +00008398 if (FLAG_count_based_interrupts) {
8399 InterruptStub interrupt_stub;
8400 check_code = interrupt_stub.GetCode();
8401 } else // NOLINT
yangguo@chromium.org56454712012-02-16 15:33:53 +00008402 { // NOLINT
8403 StackCheckStub check_stub;
8404 check_code = check_stub.GetCode();
8405 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008406 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008407 Deoptimizer::RevertStackCheckCode(*unoptimized,
8408 *check_code,
8409 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008410
8411 // Allow OSR only at nesting level zero again.
8412 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8413
8414 // If the optimization attempt succeeded, return the AST id tagged as a
8415 // smi. This tells the builtin that we need to translate the unoptimized
8416 // frame to an optimized one.
8417 if (succeeded) {
8418 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8419 return Smi::FromInt(ast_id);
8420 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008421 if (function->IsMarkedForLazyRecompilation()) {
8422 function->ReplaceCode(function->shared()->code());
8423 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008424 return Smi::FromInt(-1);
8425 }
8426}
8427
8428
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008429RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8430 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8431 return isolate->heap()->undefined_value();
8432}
8433
8434
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00008435RUNTIME_FUNCTION(MaybeObject*, Runtime_GetRootNaN) {
8436 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8437 return isolate->heap()->nan_value();
8438}
8439
8440
danno@chromium.orgc612e022011-11-10 11:38:15 +00008441RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8442 HandleScope scope(isolate);
8443 ASSERT(args.length() >= 2);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008444 int argc = args.length() - 2;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008445 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8446 Object* receiver = args[0];
danno@chromium.orgc612e022011-11-10 11:38:15 +00008447
8448 // If there are too many arguments, allocate argv via malloc.
8449 const int argv_small_size = 10;
8450 Handle<Object> argv_small_buffer[argv_small_size];
8451 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8452 Handle<Object>* argv = argv_small_buffer;
8453 if (argc > argv_small_size) {
8454 argv = new Handle<Object>[argc];
8455 if (argv == NULL) return isolate->StackOverflow();
8456 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8457 }
8458
8459 for (int i = 0; i < argc; ++i) {
8460 MaybeObject* maybe = args[1 + i];
8461 Object* object;
8462 if (!maybe->To<Object>(&object)) return maybe;
8463 argv[i] = Handle<Object>(object);
8464 }
8465
8466 bool threw;
8467 Handle<JSReceiver> hfun(fun);
8468 Handle<Object> hreceiver(receiver);
8469 Handle<Object> result =
8470 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8471
8472 if (threw) return Failure::Exception();
8473 return *result;
8474}
8475
8476
lrn@chromium.org34e60782011-09-15 07:25:40 +00008477RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8478 HandleScope scope(isolate);
8479 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008480 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008481 Handle<Object> receiver = args.at<Object>(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008482 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008483 CONVERT_SMI_ARG_CHECKED(offset, 3);
8484 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008485 ASSERT(offset >= 0);
8486 ASSERT(argc >= 0);
8487
8488 // If there are too many arguments, allocate argv via malloc.
8489 const int argv_small_size = 10;
8490 Handle<Object> argv_small_buffer[argv_small_size];
8491 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8492 Handle<Object>* argv = argv_small_buffer;
8493 if (argc > argv_small_size) {
8494 argv = new Handle<Object>[argc];
8495 if (argv == NULL) return isolate->StackOverflow();
8496 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8497 }
8498
8499 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008500 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008501 }
8502
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008503 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008504 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008505 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008506
8507 if (threw) return Failure::Exception();
8508 return *result;
8509}
8510
8511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008512RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008513 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008514 ASSERT(args.length() == 1);
8515 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8516 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8517}
8518
8519
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008520RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008521 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008522 ASSERT(args.length() == 1);
8523 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8524 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8525}
8526
8527
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008528RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008529 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008530 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008531
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008532 CONVERT_ARG_CHECKED(JSFunction, function, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008533 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008534 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008535 { MaybeObject* maybe_result =
8536 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008537 if (!maybe_result->ToObject(&result)) return maybe_result;
8538 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008539
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008540 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008541
kasper.lund7276f142008-07-30 08:49:36 +00008542 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008543}
8544
lrn@chromium.org303ada72010-10-27 09:33:13 +00008545
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008546RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8547 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008548 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008549 JSObject* extension_object;
8550 if (args[0]->IsJSObject()) {
8551 extension_object = JSObject::cast(args[0]);
8552 } else {
8553 // Convert the object to a proper JavaScript object.
8554 MaybeObject* maybe_js_object = args[0]->ToObject();
8555 if (!maybe_js_object->To(&extension_object)) {
8556 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8557 HandleScope scope(isolate);
8558 Handle<Object> handle = args.at<Object>(0);
8559 Handle<Object> result =
8560 isolate->factory()->NewTypeError("with_expression",
8561 HandleVector(&handle, 1));
8562 return isolate->Throw(*result);
8563 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008564 return maybe_js_object;
8565 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008566 }
8567 }
8568
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008569 JSFunction* function;
8570 if (args[1]->IsSmi()) {
8571 // A smi sentinel indicates a context nested inside global code rather
8572 // than some function. There is a canonical empty function that can be
8573 // gotten from the global context.
8574 function = isolate->context()->global_context()->closure();
8575 } else {
8576 function = JSFunction::cast(args[1]);
8577 }
8578
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008579 Context* context;
8580 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008581 isolate->heap()->AllocateWithContext(function,
8582 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008583 extension_object);
8584 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008585 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008586 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008587}
8588
8589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008590RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008591 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008592 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008593 String* name = String::cast(args[0]);
8594 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008595 JSFunction* function;
8596 if (args[2]->IsSmi()) {
8597 // A smi sentinel indicates a context nested inside global code rather
8598 // than some function. There is a canonical empty function that can be
8599 // gotten from the global context.
8600 function = isolate->context()->global_context()->closure();
8601 } else {
8602 function = JSFunction::cast(args[2]);
8603 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008604 Context* context;
8605 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008606 isolate->heap()->AllocateCatchContext(function,
8607 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008608 name,
8609 thrown_object);
8610 if (!maybe_context->To(&context)) return maybe_context;
8611 isolate->set_context(context);
8612 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008613}
8614
8615
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008616RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8617 NoHandleAllocation ha;
8618 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008619 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008620 JSFunction* function;
8621 if (args[1]->IsSmi()) {
8622 // A smi sentinel indicates a context nested inside global code rather
8623 // than some function. There is a canonical empty function that can be
8624 // gotten from the global context.
8625 function = isolate->context()->global_context()->closure();
8626 } else {
8627 function = JSFunction::cast(args[1]);
8628 }
8629 Context* context;
8630 MaybeObject* maybe_context =
8631 isolate->heap()->AllocateBlockContext(function,
8632 isolate->context(),
8633 scope_info);
8634 if (!maybe_context->To(&context)) return maybe_context;
8635 isolate->set_context(context);
8636 return context;
8637}
8638
8639
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00008640RUNTIME_FUNCTION(MaybeObject*, Runtime_PushModuleContext) {
8641 NoHandleAllocation ha;
8642 ASSERT(args.length() == 2);
8643 CONVERT_ARG_CHECKED(ScopeInfo, scope_info, 0);
8644 CONVERT_ARG_HANDLE_CHECKED(JSModule, instance, 1);
8645
8646 Context* context;
8647 MaybeObject* maybe_context =
8648 isolate->heap()->AllocateModuleContext(isolate->context(),
8649 scope_info);
8650 if (!maybe_context->To(&context)) return maybe_context;
8651 // Also initialize the context slot of the instance object.
8652 instance->set_context(context);
8653 isolate->set_context(context);
8654
8655 return context;
8656}
8657
8658
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008659RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008660 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008661 ASSERT(args.length() == 2);
8662
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008663 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8664 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008665
8666 int index;
8667 PropertyAttributes attributes;
8668 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008669 BindingFlags binding_flags;
8670 Handle<Object> holder = context->Lookup(name,
8671 flags,
8672 &index,
8673 &attributes,
8674 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008675
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008676 // If the slot was not found the result is true.
8677 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008678 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008679 }
8680
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008681 // If the slot was found in a context, it should be DONT_DELETE.
8682 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008683 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008684 }
8685
8686 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008687 // the global object, or the subject of a with. Try to delete it
8688 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008689 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008690 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008691}
8692
8693
ager@chromium.orga1645e22009-09-09 19:27:10 +00008694// A mechanism to return a pair of Object pointers in registers (if possible).
8695// How this is achieved is calling convention-dependent.
8696// All currently supported x86 compiles uses calling conventions that are cdecl
8697// variants where a 64-bit value is returned in two 32-bit registers
8698// (edx:eax on ia32, r1:r0 on ARM).
8699// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8700// In Win64 calling convention, a struct of two pointers is returned in memory,
8701// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008702#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008703struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008704 MaybeObject* x;
8705 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008706};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008707
lrn@chromium.org303ada72010-10-27 09:33:13 +00008708static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008709 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008710 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8711 // In Win64 they are assigned to a hidden first argument.
8712 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008713}
8714#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008715typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008716static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008717 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008718 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008719}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008720#endif
8721
8722
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008723static inline MaybeObject* Unhole(Heap* heap,
8724 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008725 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008726 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8727 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008728 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008729}
8730
8731
danno@chromium.org40cb8782011-05-25 07:58:50 +00008732static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8733 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008734 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008735 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008736 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008737 JSFunction* context_extension_function =
8738 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008739 // If the holder isn't a context extension object, we just return it
8740 // as the receiver. This allows arguments objects to be used as
8741 // receivers, but only if they are put in the context scope chain
8742 // explicitly via a with-statement.
8743 Object* constructor = holder->map()->constructor();
8744 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008745 // Fall back to using the global object as the implicit receiver if
8746 // the property turns out to be a local variable allocated in a
8747 // context extension object - introduced via eval. Implicit global
8748 // receivers are indicated with the hole value.
8749 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008750}
8751
8752
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008753static ObjectPair LoadContextSlotHelper(Arguments args,
8754 Isolate* isolate,
8755 bool throw_error) {
8756 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008757 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008758
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008759 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008760 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008761 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008762 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008763 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008764
8765 int index;
8766 PropertyAttributes attributes;
8767 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008768 BindingFlags binding_flags;
8769 Handle<Object> holder = context->Lookup(name,
8770 flags,
8771 &index,
8772 &attributes,
8773 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008774
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008775 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008776 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008777 ASSERT(holder->IsContext());
8778 // If the "property" we were looking for is a local variable, the
8779 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008780 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008781 // Use the hole as the receiver to signal that the receiver is implicit
8782 // and that the global receiver should be used (as distinguished from an
8783 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00008784 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008785 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008786 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008787 switch (binding_flags) {
8788 case MUTABLE_CHECK_INITIALIZED:
8789 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
8790 if (value->IsTheHole()) {
8791 Handle<Object> reference_error =
8792 isolate->factory()->NewReferenceError("not_defined",
8793 HandleVector(&name, 1));
8794 return MakePair(isolate->Throw(*reference_error), NULL);
8795 }
8796 // FALLTHROUGH
8797 case MUTABLE_IS_INITIALIZED:
8798 case IMMUTABLE_IS_INITIALIZED:
8799 case IMMUTABLE_IS_INITIALIZED_HARMONY:
8800 ASSERT(!value->IsTheHole());
8801 return MakePair(value, *receiver);
8802 case IMMUTABLE_CHECK_INITIALIZED:
8803 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8804 case MISSING_BINDING:
8805 UNREACHABLE();
8806 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008807 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008808 }
8809
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008810 // Otherwise, if the slot was found the holder is a context extension
8811 // object, subject of a with, or a global object. We read the named
8812 // property from it.
8813 if (!holder.is_null()) {
8814 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8815 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008816 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008817 Handle<Object> receiver_handle(object->IsGlobalObject()
8818 ? GlobalObject::cast(*object)->global_receiver()
8819 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008820
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008821 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008822 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008823 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008824 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008825 }
8826
8827 if (throw_error) {
8828 // The property doesn't exist - throw exception.
8829 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008830 isolate->factory()->NewReferenceError("not_defined",
8831 HandleVector(&name, 1));
8832 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008833 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008834 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008835 return MakePair(isolate->heap()->undefined_value(),
8836 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008837 }
8838}
8839
8840
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008841RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008842 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008843}
8844
8845
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008846RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008847 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008848}
8849
8850
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008851RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008852 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008853 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008854
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008855 Handle<Object> value(args[0], isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008856 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
8857 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00008858 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
8859 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
8860 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008861
8862 int index;
8863 PropertyAttributes attributes;
8864 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008865 BindingFlags binding_flags;
8866 Handle<Object> holder = context->Lookup(name,
8867 flags,
8868 &index,
8869 &attributes,
8870 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008871
8872 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008873 // The property was found in a context slot.
8874 Handle<Context> context = Handle<Context>::cast(holder);
8875 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
8876 context->get(index)->IsTheHole()) {
8877 Handle<Object> error =
8878 isolate->factory()->NewReferenceError("not_defined",
8879 HandleVector(&name, 1));
8880 return isolate->Throw(*error);
8881 }
8882 // Ignore if read_only variable.
8883 if ((attributes & READ_ONLY) == 0) {
8884 // Context is a fixed array and set cannot fail.
8885 context->set(index, *value);
8886 } else if (strict_mode == kStrictMode) {
8887 // Setting read only property in strict mode.
8888 Handle<Object> error =
8889 isolate->factory()->NewTypeError("strict_cannot_assign",
8890 HandleVector(&name, 1));
8891 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008892 }
8893 return *value;
8894 }
8895
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008896 // Slow case: The property is not in a context slot. It is either in a
8897 // context extension object, a property of the subject of a with, or a
8898 // property of the global object.
8899 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008900
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008901 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008902 // The property exists on the holder.
8903 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008904 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008905 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008906 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008907
8908 if (strict_mode == kStrictMode) {
8909 // Throw in strict mode (assignment to undefined variable).
8910 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008911 isolate->factory()->NewReferenceError(
8912 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008913 return isolate->Throw(*error);
8914 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008915 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008916 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008917 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008918 }
8919
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008920 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008921 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008922 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008923 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008924 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008925 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008926 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008927 // Setting read only property in strict mode.
8928 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008929 isolate->factory()->NewTypeError(
8930 "strict_cannot_assign", HandleVector(&name, 1));
8931 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008932 }
8933 return *value;
8934}
8935
8936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008937RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008938 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008939 ASSERT(args.length() == 1);
8940
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008941 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008942}
8943
8944
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008945RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008946 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008947 ASSERT(args.length() == 1);
8948
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008949 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008950}
8951
8952
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008953RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008954 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008955 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008956}
8957
8958
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008959RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008960 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008961 ASSERT(args.length() == 1);
8962
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008963 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008964 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008965 isolate->factory()->NewReferenceError("not_defined",
8966 HandleVector(&name, 1));
8967 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008968}
8969
8970
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008971RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008972 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008973
8974 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008975 if (isolate->stack_guard()->IsStackOverflow()) {
8976 NoHandleAllocation na;
8977 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008978 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008979
ulan@chromium.org812308e2012-02-29 15:58:45 +00008980 return Execution::HandleStackGuardInterrupt(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008981}
8982
8983
yangguo@chromium.org56454712012-02-16 15:33:53 +00008984RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
8985 ASSERT(args.length() == 0);
ulan@chromium.org812308e2012-02-29 15:58:45 +00008986 return Execution::HandleStackGuardInterrupt(isolate);
yangguo@chromium.org56454712012-02-16 15:33:53 +00008987}
8988
8989
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008990static int StackSize() {
8991 int n = 0;
8992 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8993 return n;
8994}
8995
8996
8997static void PrintTransition(Object* result) {
8998 // indentation
8999 { const int nmax = 80;
9000 int n = StackSize();
9001 if (n <= nmax)
9002 PrintF("%4d:%*s", n, n, "");
9003 else
9004 PrintF("%4d:%*s", n, nmax, "...");
9005 }
9006
9007 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009008 JavaScriptFrame::PrintTop(stdout, true, false);
9009 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009010 } else {
9011 // function result
9012 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009013 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009014 PrintF("\n");
9015 }
9016}
9017
9018
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009019RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009020 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009021 NoHandleAllocation ha;
9022 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009023 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009024}
9025
9026
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009027RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009028 NoHandleAllocation ha;
9029 PrintTransition(args[0]);
9030 return args[0]; // return TOS
9031}
9032
9033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009034RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009035 NoHandleAllocation ha;
9036 ASSERT(args.length() == 1);
9037
9038#ifdef DEBUG
9039 if (args[0]->IsString()) {
9040 // If we have a string, assume it's a code "marker"
9041 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009042 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009043 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009044 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9045 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009046 } else {
9047 PrintF("DebugPrint: ");
9048 }
9049 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009050 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009051 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009052 HeapObject::cast(args[0])->map()->Print();
9053 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009054#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009055 // ShortPrint is available in release mode. Print is not.
9056 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009057#endif
9058 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009059 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009060
9061 return args[0]; // return TOS
9062}
9063
9064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009065RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009066 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009067 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009068 isolate->PrintStack();
9069 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009070}
9071
9072
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009073RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009074 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009075 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009076
9077 // According to ECMA-262, section 15.9.1, page 117, the precision of
9078 // the number in a Date object representing a particular instant in
9079 // time is milliseconds. Therefore, we floor the result of getting
9080 // the OS time.
9081 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009082 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009083}
9084
9085
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009086RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009087 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009088 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009089
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009090 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009091 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009092
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009093 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009094
9095 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009096 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009097 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009098 RUNTIME_ASSERT(output->HasFastElements());
9099
9100 AssertNoAllocation no_allocation;
9101
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009102 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009103 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9104 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009105 String::FlatContent str_content = str->GetFlatContent();
9106 if (str_content.IsAscii()) {
9107 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009108 output_array,
9109 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009110 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009111 ASSERT(str_content.IsTwoByte());
9112 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009113 output_array,
9114 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009115 }
9116
9117 if (result) {
9118 return *output;
9119 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009120 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009121 }
9122}
9123
9124
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009125RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009126 NoHandleAllocation ha;
9127 ASSERT(args.length() == 1);
9128
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009129 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009130 int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x));
9131 const char* zone = OS::LocalTimezone(static_cast<double>(time));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009132 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009133}
9134
9135
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009136RUNTIME_FUNCTION(MaybeObject*, Runtime_DateToUTC) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009137 NoHandleAllocation ha;
9138 ASSERT(args.length() == 1);
9139
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009140 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009141 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
9142
9143 return isolate->heap()->NumberFromDouble(static_cast<double>(time));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009144}
9145
9146
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009147RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009148 ASSERT(args.length() == 1);
9149 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009150 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009151 return JSGlobalObject::cast(global)->global_receiver();
9152}
9153
9154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009155RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009156 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009157 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009158 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009159
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009160 source = Handle<String>(source->TryFlattenGetString());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009161 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009162 Handle<Object> result;
9163 if (source->IsSeqAsciiString()) {
9164 result = JsonParser<true>::Parse(source);
9165 } else {
9166 result = JsonParser<false>::Parse(source);
9167 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009168 if (result.is_null()) {
9169 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009170 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009171 return Failure::Exception();
9172 }
9173 return *result;
9174}
9175
9176
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009177bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9178 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009179 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9180 // Check with callback if set.
9181 AllowCodeGenerationFromStringsCallback callback =
9182 isolate->allow_code_gen_callback();
9183 if (callback == NULL) {
9184 // No callback set and code generation disallowed.
9185 return false;
9186 } else {
9187 // Callback set. Let it decide if code generation is allowed.
9188 VMState state(isolate, EXTERNAL);
9189 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009190 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009191}
9192
9193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009194RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009195 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009196 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009197 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009198
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009199 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009200 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009201
9202 // Check if global context allows code generation from
9203 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009204 if (context->allow_code_gen_from_strings()->IsFalse() &&
9205 !CodeGenerationFromStringsAllowed(isolate, context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009206 return isolate->Throw(*isolate->factory()->NewError(
9207 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9208 }
9209
9210 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009211 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009212 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009213 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009214 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009215 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9216 context,
9217 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009218 return *fun;
9219}
9220
9221
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009222static ObjectPair CompileGlobalEval(Isolate* isolate,
9223 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009224 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009225 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009226 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009227 Handle<Context> context = Handle<Context>(isolate->context());
9228 Handle<Context> global_context = Handle<Context>(context->global_context());
9229
9230 // Check if global context allows code generation from
9231 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009232 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9233 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009234 isolate->Throw(*isolate->factory()->NewError(
9235 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9236 return MakePair(Failure::Exception(), NULL);
9237 }
9238
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009239 // Deal with a normal eval call with a string argument. Compile it
9240 // and return the compiled function bound in the local context.
9241 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9242 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009243 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009244 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009245 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009246 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009247 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009248 Handle<JSFunction> compiled =
9249 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009250 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009251 return MakePair(*compiled, *receiver);
9252}
9253
9254
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009255RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009256 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009257
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009258 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009259 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009260
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009261 // If "eval" didn't refer to the original GlobalEval, it's not a
9262 // direct call to eval.
9263 // (And even if it is, but the first argument isn't a string, just let
9264 // execution default to an indirect call to eval, which will also return
9265 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009266 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009267 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009268 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009269 }
9270
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009271 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009272 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009273 return CompileGlobalEval(isolate,
9274 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009275 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009276 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009277 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009278}
9279
9280
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009281RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009282 // This utility adjusts the property attributes for newly created Function
9283 // object ("new Function(...)") by changing the map.
9284 // All it does is changing the prototype property to enumerable
9285 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009286 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009287 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009288 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009289
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009290 Handle<Map> map = func->shared()->is_classic_mode()
9291 ? isolate->function_instance_map()
9292 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009293
9294 ASSERT(func->map()->instance_type() == map->instance_type());
9295 ASSERT(func->map()->instance_size() == map->instance_size());
9296 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009297 return *func;
9298}
9299
9300
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009301RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009302 // Allocate a block of memory in NewSpace (filled with a filler).
9303 // Use as fallback for allocation in generated code when NewSpace
9304 // is full.
9305 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009306 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009307 int size = size_smi->value();
9308 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9309 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009310 Heap* heap = isolate->heap();
9311 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009312 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009313 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009314 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009315 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009316 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009317 }
9318 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009319 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009320}
9321
9322
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009323// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009324// array. Returns true if the element was pushed on the stack and
9325// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009326RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009327 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009328 CONVERT_ARG_CHECKED(JSArray, array, 0);
9329 CONVERT_ARG_CHECKED(JSObject, element, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009330 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009331 int length = Smi::cast(array->length())->value();
9332 FixedArray* elements = FixedArray::cast(array->elements());
9333 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009334 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009335 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009336 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009337 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009338 { MaybeObject* maybe_obj =
9339 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009340 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9341 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009342 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009343}
9344
9345
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009346/**
9347 * A simple visitor visits every element of Array's.
9348 * The backend storage can be a fixed array for fast elements case,
9349 * or a dictionary for sparse array. Since Dictionary is a subtype
9350 * of FixedArray, the class can be used by both fast and slow cases.
9351 * The second parameter of the constructor, fast_elements, specifies
9352 * whether the storage is a FixedArray or Dictionary.
9353 *
9354 * An index limit is used to deal with the situation that a result array
9355 * length overflows 32-bit non-negative integer.
9356 */
9357class ArrayConcatVisitor {
9358 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009359 ArrayConcatVisitor(Isolate* isolate,
9360 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009361 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009362 isolate_(isolate),
9363 storage_(Handle<FixedArray>::cast(
9364 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009365 index_offset_(0u),
9366 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009367
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009368 ~ArrayConcatVisitor() {
9369 clear_storage();
9370 }
9371
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009372 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009373 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009374 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009375
9376 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009377 if (index < static_cast<uint32_t>(storage_->length())) {
9378 storage_->set(index, *elm);
9379 return;
9380 }
9381 // Our initial estimate of length was foiled, possibly by
9382 // getters on the arrays increasing the length of later arrays
9383 // during iteration.
9384 // This shouldn't happen in anything but pathological cases.
9385 SetDictionaryMode(index);
9386 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009387 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009388 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009389 Handle<SeededNumberDictionary> dict(
9390 SeededNumberDictionary::cast(*storage_));
9391 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009392 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009393 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009394 // Dictionary needed to grow.
9395 clear_storage();
9396 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009397 }
9398}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009399
9400 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009401 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9402 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009403 } else {
9404 index_offset_ += delta;
9405 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009406 }
9407
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009408 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009409 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009410 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009411 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009412 Handle<Map> map;
9413 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009414 map = isolate_->factory()->GetElementsTransitionMap(array,
9415 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009416 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009417 map = isolate_->factory()->GetElementsTransitionMap(array,
9418 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009419 }
9420 array->set_map(*map);
9421 array->set_length(*length);
9422 array->set_elements(*storage_);
9423 return array;
9424 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009425
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009426 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009427 // Convert storage to dictionary mode.
9428 void SetDictionaryMode(uint32_t index) {
9429 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009430 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009431 Handle<SeededNumberDictionary> slow_storage(
9432 isolate_->factory()->NewSeededNumberDictionary(
9433 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009434 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9435 for (uint32_t i = 0; i < current_length; i++) {
9436 HandleScope loop_scope;
9437 Handle<Object> element(current_storage->get(i));
9438 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009439 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009440 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009441 if (!new_storage.is_identical_to(slow_storage)) {
9442 slow_storage = loop_scope.CloseAndEscape(new_storage);
9443 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009444 }
9445 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009446 clear_storage();
9447 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009448 fast_elements_ = false;
9449 }
9450
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009451 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009452 isolate_->global_handles()->Destroy(
9453 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009454 }
9455
9456 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009457 storage_ = Handle<FixedArray>::cast(
9458 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009459 }
9460
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009461 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009462 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009463 // Index after last seen index. Always less than or equal to
9464 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009465 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009466 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009467};
9468
9469
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009470static uint32_t EstimateElementCount(Handle<JSArray> array) {
9471 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9472 int element_count = 0;
9473 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009474 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009475 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009476 // Fast elements can't have lengths that are not representable by
9477 // a 32-bit signed integer.
9478 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9479 int fast_length = static_cast<int>(length);
9480 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9481 for (int i = 0; i < fast_length; i++) {
9482 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009483 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009484 break;
9485 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009486 case FAST_DOUBLE_ELEMENTS:
9487 // TODO(1810): Decide if it's worthwhile to implement this.
9488 UNREACHABLE();
9489 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009490 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009491 Handle<SeededNumberDictionary> dictionary(
9492 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009493 int capacity = dictionary->Capacity();
9494 for (int i = 0; i < capacity; i++) {
9495 Handle<Object> key(dictionary->KeyAt(i));
9496 if (dictionary->IsKey(*key)) {
9497 element_count++;
9498 }
9499 }
9500 break;
9501 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009502 case NON_STRICT_ARGUMENTS_ELEMENTS:
9503 case EXTERNAL_BYTE_ELEMENTS:
9504 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9505 case EXTERNAL_SHORT_ELEMENTS:
9506 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9507 case EXTERNAL_INT_ELEMENTS:
9508 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9509 case EXTERNAL_FLOAT_ELEMENTS:
9510 case EXTERNAL_DOUBLE_ELEMENTS:
9511 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009512 // External arrays are always dense.
9513 return length;
9514 }
9515 // As an estimate, we assume that the prototype doesn't contain any
9516 // inherited elements.
9517 return element_count;
9518}
9519
9520
9521
9522template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009523static void IterateExternalArrayElements(Isolate* isolate,
9524 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009525 bool elements_are_ints,
9526 bool elements_are_guaranteed_smis,
9527 ArrayConcatVisitor* visitor) {
9528 Handle<ExternalArrayClass> array(
9529 ExternalArrayClass::cast(receiver->elements()));
9530 uint32_t len = static_cast<uint32_t>(array->length());
9531
9532 ASSERT(visitor != NULL);
9533 if (elements_are_ints) {
9534 if (elements_are_guaranteed_smis) {
9535 for (uint32_t j = 0; j < len; j++) {
9536 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009537 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009538 visitor->visit(j, e);
9539 }
9540 } else {
9541 for (uint32_t j = 0; j < len; j++) {
9542 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009543 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009544 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9545 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9546 visitor->visit(j, e);
9547 } else {
9548 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009549 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009550 visitor->visit(j, e);
9551 }
9552 }
9553 }
9554 } else {
9555 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009556 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009557 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009558 visitor->visit(j, e);
9559 }
9560 }
9561}
9562
9563
9564// Used for sorting indices in a List<uint32_t>.
9565static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9566 uint32_t a = *ap;
9567 uint32_t b = *bp;
9568 return (a == b) ? 0 : (a < b) ? -1 : 1;
9569}
9570
9571
9572static void CollectElementIndices(Handle<JSObject> object,
9573 uint32_t range,
9574 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009575 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009576 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009577 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009578 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009579 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9580 uint32_t length = static_cast<uint32_t>(elements->length());
9581 if (range < length) length = range;
9582 for (uint32_t i = 0; i < length; i++) {
9583 if (!elements->get(i)->IsTheHole()) {
9584 indices->Add(i);
9585 }
9586 }
9587 break;
9588 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009589 case FAST_DOUBLE_ELEMENTS: {
9590 // TODO(1810): Decide if it's worthwhile to implement this.
9591 UNREACHABLE();
9592 break;
9593 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009594 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009595 Handle<SeededNumberDictionary> dict(
9596 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009597 uint32_t capacity = dict->Capacity();
9598 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009599 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009600 Handle<Object> k(dict->KeyAt(j));
9601 if (dict->IsKey(*k)) {
9602 ASSERT(k->IsNumber());
9603 uint32_t index = static_cast<uint32_t>(k->Number());
9604 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009605 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009606 }
9607 }
9608 }
9609 break;
9610 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009611 default: {
9612 int dense_elements_length;
9613 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009614 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009615 dense_elements_length =
9616 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009617 break;
9618 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009619 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009620 dense_elements_length =
9621 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009622 break;
9623 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009624 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009625 dense_elements_length =
9626 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009627 break;
9628 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009629 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009630 dense_elements_length =
9631 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009632 break;
9633 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009634 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009635 dense_elements_length =
9636 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009637 break;
9638 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009639 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009640 dense_elements_length =
9641 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009642 break;
9643 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009644 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009645 dense_elements_length =
9646 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009647 break;
9648 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009649 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009650 dense_elements_length =
9651 ExternalFloatArray::cast(object->elements())->length();
9652 break;
9653 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009654 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009655 dense_elements_length =
9656 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009657 break;
9658 }
9659 default:
9660 UNREACHABLE();
9661 dense_elements_length = 0;
9662 break;
9663 }
9664 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9665 if (range <= length) {
9666 length = range;
9667 // We will add all indices, so we might as well clear it first
9668 // and avoid duplicates.
9669 indices->Clear();
9670 }
9671 for (uint32_t i = 0; i < length; i++) {
9672 indices->Add(i);
9673 }
9674 if (length == range) return; // All indices accounted for already.
9675 break;
9676 }
9677 }
9678
9679 Handle<Object> prototype(object->GetPrototype());
9680 if (prototype->IsJSObject()) {
9681 // The prototype will usually have no inherited element indices,
9682 // but we have to check.
9683 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9684 }
9685}
9686
9687
9688/**
9689 * A helper function that visits elements of a JSArray in numerical
9690 * order.
9691 *
9692 * The visitor argument called for each existing element in the array
9693 * with the element index and the element's value.
9694 * Afterwards it increments the base-index of the visitor by the array
9695 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009696 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009697 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009698static bool IterateElements(Isolate* isolate,
9699 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009700 ArrayConcatVisitor* visitor) {
9701 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9702 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009703 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009704 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009705 // Run through the elements FixedArray and use HasElement and GetElement
9706 // to check the prototype for missing elements.
9707 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9708 int fast_length = static_cast<int>(length);
9709 ASSERT(fast_length <= elements->length());
9710 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009711 HandleScope loop_scope(isolate);
9712 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009713 if (!element_value->IsTheHole()) {
9714 visitor->visit(j, element_value);
9715 } else if (receiver->HasElement(j)) {
9716 // Call GetElement on receiver, not its prototype, or getters won't
9717 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009718 element_value = Object::GetElement(receiver, j);
9719 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009720 visitor->visit(j, element_value);
9721 }
9722 }
9723 break;
9724 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009725 case FAST_DOUBLE_ELEMENTS: {
9726 // TODO(1810): Decide if it's worthwhile to implement this.
9727 UNREACHABLE();
9728 break;
9729 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009730 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009731 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009732 List<uint32_t> indices(dict->Capacity() / 2);
9733 // Collect all indices in the object and the prototypes less
9734 // than length. This might introduce duplicates in the indices list.
9735 CollectElementIndices(receiver, length, &indices);
9736 indices.Sort(&compareUInt32);
9737 int j = 0;
9738 int n = indices.length();
9739 while (j < n) {
9740 HandleScope loop_scope;
9741 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009742 Handle<Object> element = Object::GetElement(receiver, index);
9743 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009744 visitor->visit(index, element);
9745 // Skip to next different index (i.e., omit duplicates).
9746 do {
9747 j++;
9748 } while (j < n && indices[j] == index);
9749 }
9750 break;
9751 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009752 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009753 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9754 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009755 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009756 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009757 visitor->visit(j, e);
9758 }
9759 break;
9760 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009761 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009762 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009763 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009764 break;
9765 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009766 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009767 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009768 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009769 break;
9770 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009771 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009772 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009773 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009774 break;
9775 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009776 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009777 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009778 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009779 break;
9780 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009781 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009782 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009783 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009784 break;
9785 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009786 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009787 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009788 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009789 break;
9790 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009791 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009792 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009793 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009794 break;
9795 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009796 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009797 IterateExternalArrayElements<ExternalDoubleArray, double>(
9798 isolate, receiver, false, false, visitor);
9799 break;
9800 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009801 default:
9802 UNREACHABLE();
9803 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009804 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009805 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009806 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009807}
9808
9809
9810/**
9811 * Array::concat implementation.
9812 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009813 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009814 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009815 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009816RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009817 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009818 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009819
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009820 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009821 int argument_count = static_cast<int>(arguments->length()->Number());
9822 RUNTIME_ASSERT(arguments->HasFastElements());
9823 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009824
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009825 // Pass 1: estimate the length and number of elements of the result.
9826 // The actual length can be larger if any of the arguments have getters
9827 // that mutate other arguments (but will otherwise be precise).
9828 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009829
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009830 uint32_t estimate_result_length = 0;
9831 uint32_t estimate_nof_elements = 0;
9832 {
9833 for (int i = 0; i < argument_count; i++) {
9834 HandleScope loop_scope;
9835 Handle<Object> obj(elements->get(i));
9836 uint32_t length_estimate;
9837 uint32_t element_estimate;
9838 if (obj->IsJSArray()) {
9839 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009840 // TODO(1810): Find out if it's worthwhile to properly support
9841 // arbitrary ElementsKinds. For now, pessimistically transition to
9842 // FAST_ELEMENTS.
9843 if (array->HasFastDoubleElements()) {
9844 array = Handle<JSArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009845 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009846 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009847 length_estimate =
9848 static_cast<uint32_t>(array->length()->Number());
9849 element_estimate =
9850 EstimateElementCount(array);
9851 } else {
9852 length_estimate = 1;
9853 element_estimate = 1;
9854 }
9855 // Avoid overflows by capping at kMaxElementCount.
9856 if (JSObject::kMaxElementCount - estimate_result_length <
9857 length_estimate) {
9858 estimate_result_length = JSObject::kMaxElementCount;
9859 } else {
9860 estimate_result_length += length_estimate;
9861 }
9862 if (JSObject::kMaxElementCount - estimate_nof_elements <
9863 element_estimate) {
9864 estimate_nof_elements = JSObject::kMaxElementCount;
9865 } else {
9866 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009867 }
9868 }
9869 }
9870
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009871 // If estimated number of elements is more than half of length, a
9872 // fixed array (fast case) is more time and space-efficient than a
9873 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009874 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009875
9876 Handle<FixedArray> storage;
9877 if (fast_case) {
9878 // The backing storage array must have non-existing elements to
9879 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009880 storage = isolate->factory()->NewFixedArrayWithHoles(
9881 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009882 } else {
9883 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9884 uint32_t at_least_space_for = estimate_nof_elements +
9885 (estimate_nof_elements >> 2);
9886 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009887 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009888 }
9889
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009890 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009891
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009892 for (int i = 0; i < argument_count; i++) {
9893 Handle<Object> obj(elements->get(i));
9894 if (obj->IsJSArray()) {
9895 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009896 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009897 return Failure::Exception();
9898 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009899 } else {
9900 visitor.visit(0, obj);
9901 visitor.increase_index_offset(1);
9902 }
9903 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009904
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009905 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009906}
9907
9908
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009909// This will not allocate (flatten the string), but it may run
9910// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009911RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009912 NoHandleAllocation ha;
9913 ASSERT(args.length() == 1);
9914
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009915 CONVERT_ARG_CHECKED(String, string, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009916 StringInputBuffer buffer(string);
9917 while (buffer.has_more()) {
9918 uint16_t character = buffer.GetNext();
9919 PrintF("%c", character);
9920 }
9921 return string;
9922}
9923
ager@chromium.org5ec48922009-05-05 07:25:34 +00009924// Moves all own elements of an object, that are below a limit, to positions
9925// starting at zero. All undefined values are placed after non-undefined values,
9926// and are followed by non-existing element. Does not change the length
9927// property.
9928// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009929RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009930 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009931 CONVERT_ARG_CHECKED(JSObject, object, 0);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009932 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9933 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009934}
9935
9936
9937// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009938RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009939 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009940 CONVERT_ARG_CHECKED(JSArray, from, 0);
9941 CONVERT_ARG_CHECKED(JSArray, to, 1);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009942 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009943 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009944 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009945 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9946 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009947 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009948 } else if (new_elements->map() ==
9949 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009950 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009951 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009952 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009953 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00009954 maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009955 Object* new_map;
9956 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009957 to->set_map(Map::cast(new_map));
9958 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009959 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009960 Object* obj;
9961 { MaybeObject* maybe_obj = from->ResetElements();
9962 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9963 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009964 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009965 return to;
9966}
9967
9968
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009969// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009970RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009971 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009972 CONVERT_ARG_CHECKED(JSObject, object, 0);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009973 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009974 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009975 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
9976 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009977 } else if (object->IsJSArray()) {
9978 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009979 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009980 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009981 }
9982}
9983
9984
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009985RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009986 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009987
9988 ASSERT_EQ(3, args.length());
9989
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009990 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009991 Handle<Object> key1 = args.at<Object>(1);
9992 Handle<Object> key2 = args.at<Object>(2);
9993
9994 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009995 if (!key1->ToArrayIndex(&index1)
9996 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009997 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009998 }
9999
ager@chromium.orgac091b72010-05-05 07:34:42 +000010000 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010001 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010002 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010003 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010004 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010005
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010006 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000010007 isolate, JSObject::SetElement(jsobject, index1, tmp2, NONE, kStrictMode));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010008 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000010009 isolate, JSObject::SetElement(jsobject, index2, tmp1, NONE, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010010
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010011 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010012}
10013
10014
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010015// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010016// might have elements. Can either return keys (positive integers) or
10017// intervals (pair of a negative integer (-start-1) followed by a
10018// positive (length)) or undefined values.
10019// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010020RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010021 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010022 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010023 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010024 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010025 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010026 // Create an array and get all the keys into it, then remove all the
10027 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010028 bool threw = false;
10029 Handle<FixedArray> keys =
10030 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10031 if (threw) return Failure::Exception();
10032
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010033 int keys_length = keys->length();
10034 for (int i = 0; i < keys_length; i++) {
10035 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010036 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010037 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010038 // Zap invalid keys.
10039 keys->set_undefined(i);
10040 }
10041 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010042 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010043 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010044 ASSERT(array->HasFastElements() ||
10045 array->HasFastSmiOnlyElements() ||
10046 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010047 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010048 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010049 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010050 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010051 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010052 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010053 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010054 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010055 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010056 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010057 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010058 }
10059}
10060
10061
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010062RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010063 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010064 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10065 CONVERT_ARG_CHECKED(String, name, 1);
10066 CONVERT_SMI_ARG_CHECKED(flag, 2);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000010067 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
10068 return obj->LookupAccessor(name, component);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010069}
10070
10071
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010072#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010073RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010074 ASSERT(args.length() == 0);
10075 return Execution::DebugBreakHelper();
10076}
10077
10078
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010079// Helper functions for wrapping and unwrapping stack frame ids.
10080static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010081 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010082 return Smi::FromInt(id >> 2);
10083}
10084
10085
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010086static StackFrame::Id UnwrapFrameId(int wrapped) {
10087 return static_cast<StackFrame::Id>(wrapped << 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010088}
10089
10090
10091// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010092// args[0]: debug event listener function to set or null or undefined for
10093// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010094// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010095RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010096 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010097 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10098 args[0]->IsUndefined() ||
10099 args[0]->IsNull());
10100 Handle<Object> callback = args.at<Object>(0);
10101 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010102 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010103
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010104 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010105}
10106
10107
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010108RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010109 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010110 isolate->stack_guard()->DebugBreak();
10111 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010112}
10113
10114
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010115static MaybeObject* DebugLookupResultValue(Heap* heap,
10116 Object* receiver,
10117 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010118 LookupResult* result,
10119 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010120 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010121 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010122 case NORMAL:
10123 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010124 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010125 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010126 }
10127 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010128 case FIELD:
10129 value =
10130 JSObject::cast(
10131 result->holder())->FastPropertyAt(result->GetFieldIndex());
10132 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010133 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010134 }
10135 return value;
10136 case CONSTANT_FUNCTION:
10137 return result->GetConstantFunction();
10138 case CALLBACKS: {
10139 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010140 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010141 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10142 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010143 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010144 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010145 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010146 maybe_value = heap->isolate()->pending_exception();
10147 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010148 if (caught_exception != NULL) {
10149 *caught_exception = true;
10150 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010151 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010152 }
10153 return value;
10154 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010155 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010156 }
10157 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010158 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010159 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010160 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010161 case CONSTANT_TRANSITION:
10162 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010163 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010164 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010165 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010166 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010167 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010168 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010169 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010170}
10171
10172
ager@chromium.org32912102009-01-16 10:38:43 +000010173// Get debugger related details for an object property.
10174// args[0]: object holding property
10175// args[1]: name of the property
10176//
10177// The array returned contains the following information:
10178// 0: Property value
10179// 1: Property details
10180// 2: Property value is exception
10181// 3: Getter function if defined
10182// 4: Setter function if defined
10183// Items 2-4 are only filled if the property has either a getter or a setter
10184// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010185RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010186 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010187
10188 ASSERT(args.length() == 2);
10189
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010190 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10191 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010192
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010193 // Make sure to set the current context to the context before the debugger was
10194 // entered (if the debugger is entered). The reason for switching context here
10195 // is that for some property lookups (accessors and interceptors) callbacks
10196 // into the embedding application can occour, and the embedding application
10197 // could have the assumption that its own global context is the current
10198 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010199 SaveContext save(isolate);
10200 if (isolate->debug()->InDebugger()) {
10201 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010202 }
10203
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010204 // Skip the global proxy as it has no properties and always delegates to the
10205 // real global object.
10206 if (obj->IsJSGlobalProxy()) {
10207 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10208 }
10209
10210
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010211 // Check if the name is trivially convertible to an index and get the element
10212 // if so.
10213 uint32_t index;
10214 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010215 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010216 Object* element_or_char;
10217 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010218 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010219 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10220 return maybe_element_or_char;
10221 }
10222 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010223 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010224 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010225 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010226 }
10227
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010228 // Find the number of objects making up this.
10229 int length = LocalPrototypeChainLength(*obj);
10230
10231 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010232 Handle<JSObject> jsproto = obj;
10233 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010234 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010235 jsproto->LocalLookup(*name, &result);
10236 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010237 // LookupResult is not GC safe as it holds raw object pointers.
10238 // GC can happen later in this code so put the required fields into
10239 // local variables using handles when required for later use.
10240 PropertyType result_type = result.type();
10241 Handle<Object> result_callback_obj;
10242 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010243 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10244 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010245 }
10246 Smi* property_details = result.GetPropertyDetails().AsSmi();
10247 // DebugLookupResultValue can cause GC so details from LookupResult needs
10248 // to be copied to handles before this.
10249 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010250 Object* raw_value;
10251 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010252 DebugLookupResultValue(isolate->heap(), *obj, *name,
10253 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010254 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10255 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010256 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010257
10258 // If the callback object is a fixed array then it contains JavaScript
10259 // getter and/or setter.
10260 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010261 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010262 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010263 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010264 details->set(0, *value);
10265 details->set(1, property_details);
10266 if (hasJavaScriptAccessors) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010267 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010268 details->set(2, isolate->heap()->ToBoolean(caught_exception));
danno@chromium.org88aa0582012-03-23 15:11:57 +000010269 details->set(3, accessors->GetComponent(ACCESSOR_GETTER));
10270 details->set(4, accessors->GetComponent(ACCESSOR_SETTER));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010271 }
10272
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010273 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010274 }
10275 if (i < length - 1) {
10276 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10277 }
10278 }
10279
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010280 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010281}
10282
10283
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010284RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010285 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010286
10287 ASSERT(args.length() == 2);
10288
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010289 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10290 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010291
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010292 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010293 obj->Lookup(*name, &result);
10294 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010295 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010296 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010297 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010298}
10299
10300
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010301// Return the property type calculated from the property details.
10302// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010303RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010304 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010305 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10306 return Smi::FromInt(static_cast<int>(details.type()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010307}
10308
10309
10310// Return the property attribute calculated from the property details.
10311// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010312RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010313 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010314 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10315 return Smi::FromInt(static_cast<int>(details.attributes()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010316}
10317
10318
10319// Return the property insertion index calculated from the property details.
10320// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010321RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010322 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010323 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10324 return Smi::FromInt(details.index());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010325}
10326
10327
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010328// Return property value from named interceptor.
10329// args[0]: object
10330// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010331RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010332 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010333 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010334 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010335 RUNTIME_ASSERT(obj->HasNamedInterceptor());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010336 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010337
10338 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010339 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010340}
10341
10342
10343// Return element value from indexed interceptor.
10344// args[0]: object
10345// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010346RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010347 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010348 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010349 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010350 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10351 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10352
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010353 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010354}
10355
10356
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010357RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010358 ASSERT(args.length() >= 1);
10359 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010360 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010361 if (isolate->debug()->break_id() == 0 ||
10362 break_id != isolate->debug()->break_id()) {
10363 return isolate->Throw(
10364 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010365 }
10366
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010367 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010368}
10369
10370
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010371RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010372 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010373 ASSERT(args.length() == 1);
10374
10375 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010376 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010377 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10378 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010379 if (!maybe_result->ToObject(&result)) return maybe_result;
10380 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010381
10382 // Count all frames which are relevant to debugging stack trace.
10383 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010384 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010385 if (id == StackFrame::NO_ID) {
10386 // If there is no JavaScript stack frame count is 0.
10387 return Smi::FromInt(0);
10388 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010389
10390 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10391 n += it.frame()->GetInlineCount();
10392 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010393 return Smi::FromInt(n);
10394}
10395
10396
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010397class FrameInspector {
10398 public:
10399 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010400 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010401 Isolate* isolate)
10402 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10403 // Calculate the deoptimized frame.
10404 if (frame->is_optimized()) {
10405 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010406 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010407 }
10408 has_adapted_arguments_ = frame_->has_adapted_arguments();
ulan@chromium.org967e2702012-02-28 09:49:15 +000010409 is_bottommost_ = inlined_jsframe_index == 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010410 is_optimized_ = frame_->is_optimized();
10411 }
10412
10413 ~FrameInspector() {
10414 // Get rid of the calculated deoptimized frame if any.
10415 if (deoptimized_frame_ != NULL) {
10416 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10417 isolate_);
10418 }
10419 }
10420
10421 int GetParametersCount() {
10422 return is_optimized_
10423 ? deoptimized_frame_->parameters_count()
10424 : frame_->ComputeParametersCount();
10425 }
10426 int expression_count() { return deoptimized_frame_->expression_count(); }
10427 Object* GetFunction() {
10428 return is_optimized_
10429 ? deoptimized_frame_->GetFunction()
10430 : frame_->function();
10431 }
10432 Object* GetParameter(int index) {
10433 return is_optimized_
10434 ? deoptimized_frame_->GetParameter(index)
10435 : frame_->GetParameter(index);
10436 }
10437 Object* GetExpression(int index) {
10438 return is_optimized_
10439 ? deoptimized_frame_->GetExpression(index)
10440 : frame_->GetExpression(index);
10441 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010442 int GetSourcePosition() {
10443 return is_optimized_
10444 ? deoptimized_frame_->GetSourcePosition()
10445 : frame_->LookupCode()->SourcePosition(frame_->pc());
10446 }
ulan@chromium.org967e2702012-02-28 09:49:15 +000010447 bool IsConstructor() {
10448 return is_optimized_ && !is_bottommost_
10449 ? deoptimized_frame_->HasConstructStub()
10450 : frame_->IsConstructor();
10451 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010452
10453 // To inspect all the provided arguments the frame might need to be
10454 // replaced with the arguments frame.
10455 void SetArgumentsFrame(JavaScriptFrame* frame) {
10456 ASSERT(has_adapted_arguments_);
10457 frame_ = frame;
10458 is_optimized_ = frame_->is_optimized();
10459 ASSERT(!is_optimized_);
10460 }
10461
10462 private:
10463 JavaScriptFrame* frame_;
10464 DeoptimizedFrameInfo* deoptimized_frame_;
10465 Isolate* isolate_;
10466 bool is_optimized_;
ulan@chromium.org967e2702012-02-28 09:49:15 +000010467 bool is_bottommost_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010468 bool has_adapted_arguments_;
10469
10470 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10471};
10472
10473
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010474static const int kFrameDetailsFrameIdIndex = 0;
10475static const int kFrameDetailsReceiverIndex = 1;
10476static const int kFrameDetailsFunctionIndex = 2;
10477static const int kFrameDetailsArgumentCountIndex = 3;
10478static const int kFrameDetailsLocalCountIndex = 4;
10479static const int kFrameDetailsSourcePositionIndex = 5;
10480static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010481static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010482static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010483static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010484
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010485
10486static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10487 JavaScriptFrame* frame) {
10488 SaveContext* save = isolate->save_context();
10489 while (save != NULL && !save->IsBelowFrame(frame)) {
10490 save = save->prev();
10491 }
10492 ASSERT(save != NULL);
10493 return save;
10494}
10495
10496
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010497// Return an array with frame details
10498// args[0]: number: break id
10499// args[1]: number: frame index
10500//
10501// The array returned contains the following information:
10502// 0: Frame id
10503// 1: Receiver
10504// 2: Function
10505// 3: Argument count
10506// 4: Local count
10507// 5: Source position
10508// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010509// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010510// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010511// Arguments name, value
10512// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010513// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010514RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010515 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010516 ASSERT(args.length() == 2);
10517
10518 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010519 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010520 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10521 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010522 if (!maybe_check->ToObject(&check)) return maybe_check;
10523 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010524 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010525 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010526
10527 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010528 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010529 if (id == StackFrame::NO_ID) {
10530 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010531 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010532 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010533
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010534 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010535 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010536 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010537 if (index < count + it.frame()->GetInlineCount()) break;
10538 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010539 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010540 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010541
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010542 bool is_optimized = it.frame()->is_optimized();
10543
10544 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10545 if (is_optimized) {
10546 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010547 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010548 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010549 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010550
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010551 // Traverse the saved contexts chain to find the active context for the
10552 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010553 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010554
10555 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010556 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010557
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010558 // Find source position in unoptimized code.
10559 int position = frame_inspector.GetSourcePosition();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010560
ulan@chromium.org967e2702012-02-28 09:49:15 +000010561 // Check for constructor frame.
10562 bool constructor = frame_inspector.IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010563
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010564 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010565 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010566 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010567 Handle<ScopeInfo> scope_info(shared->scope_info());
10568 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010569
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010570 // Get the locals names and values into a temporary array.
10571 //
10572 // TODO(1240907): Hide compiler-introduced stack variables
10573 // (e.g. .result)? For users of the debugger, they will probably be
10574 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010575 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010576 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010577
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010578 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010579 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010580 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010581 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010582 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010583 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010584 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010585 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010586 // Get the context containing declarations.
10587 Handle<Context> context(
10588 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010589 for (; i < scope_info->LocalCount(); ++i) {
10590 Handle<String> name(scope_info->LocalName(i));
10591 VariableMode mode;
10592 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010593 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010594 locals->set(i * 2 + 1, context->get(
10595 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010596 }
10597 }
10598
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010599 // Check whether this frame is positioned at return. If not top
10600 // frame or if the frame is optimized it cannot be at a return.
10601 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010602 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010603 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010604 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010605
10606 // If positioned just before return find the value to be returned and add it
10607 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010608 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010609 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010610 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010611 Address internal_frame_sp = NULL;
10612 while (!it2.done()) {
10613 if (it2.frame()->is_internal()) {
10614 internal_frame_sp = it2.frame()->sp();
10615 } else {
10616 if (it2.frame()->is_java_script()) {
10617 if (it2.frame()->id() == it.frame()->id()) {
10618 // The internal frame just before the JavaScript frame contains the
10619 // value to return on top. A debug break at return will create an
10620 // internal frame to store the return value (eax/rax/r0) before
10621 // entering the debug break exit frame.
10622 if (internal_frame_sp != NULL) {
10623 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010624 Handle<Object>(Memory::Object_at(internal_frame_sp),
10625 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010626 break;
10627 }
10628 }
10629 }
10630
10631 // Indicate that the previous frame was not an internal frame.
10632 internal_frame_sp = NULL;
10633 }
10634 it2.Advance();
10635 }
10636 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010637
10638 // Now advance to the arguments adapter frame (if any). It contains all
10639 // the provided parameters whereas the function frame always have the number
10640 // of arguments matching the functions parameters. The rest of the
10641 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010642 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010643 it.AdvanceToArgumentsFrame();
10644 frame_inspector.SetArgumentsFrame(it.frame());
10645 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010646
10647 // Find the number of arguments to fill. At least fill the number of
10648 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010649 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010650 if (argument_count < frame_inspector.GetParametersCount()) {
10651 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010652 }
10653
10654 // Calculate the size of the result.
10655 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010656 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010657 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010658 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010659
10660 // Add the frame id.
10661 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10662
10663 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010664 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010665
10666 // Add the arguments count.
10667 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10668
10669 // Add the locals count
10670 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010671 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010672
10673 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010674 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010675 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10676 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010677 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010678 }
10679
10680 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010681 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010682
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010683 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010684 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010685
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010686 // Add flags to indicate information on whether this frame is
10687 // bit 0: invoked in the debugger context.
10688 // bit 1: optimized frame.
10689 // bit 2: inlined in optimized frame
10690 int flags = 0;
10691 if (*save->context() == *isolate->debug()->debug_context()) {
10692 flags |= 1 << 0;
10693 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010694 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010695 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010696 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010697 }
10698 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010699
10700 // Fill the dynamic part.
10701 int details_index = kFrameDetailsFirstDynamicIndex;
10702
10703 // Add arguments name and value.
10704 for (int i = 0; i < argument_count; i++) {
10705 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010706 if (i < scope_info->ParameterCount()) {
10707 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010708 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010709 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010710 }
10711
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010712 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010713 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010714 // Get the value from the stack.
10715 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010716 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010717 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010718 }
10719 }
10720
10721 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010722 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010723 details->set(details_index++, locals->get(i));
10724 }
10725
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010726 // Add the value being returned.
10727 if (at_return) {
10728 details->set(details_index++, *return_value);
10729 }
10730
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010731 // Add the receiver (same as in function frame).
10732 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10733 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010734 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010735 if (!receiver->IsJSObject() &&
10736 shared->is_classic_mode() &&
10737 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010738 // If the receiver is not a JSObject and the function is not a
10739 // builtin or strict-mode we have hit an optimization where a
10740 // value object is not converted into a wrapped JS objects. To
10741 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010742 // by creating correct wrapper object based on the calling frame's
10743 // global context.
10744 it.Advance();
10745 Handle<Context> calling_frames_global_context(
10746 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010747 receiver =
10748 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010749 }
10750 details->set(kFrameDetailsReceiverIndex, *receiver);
10751
10752 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010753 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010754}
10755
10756
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010757// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010758static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010759 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010760 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010761 Handle<Context> context,
10762 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010763 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010764 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
10765 VariableMode mode;
10766 InitializationFlag init_flag;
10767 int context_index = scope_info->ContextSlotIndex(
10768 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010769
whesse@chromium.org7b260152011-06-20 15:33:18 +000010770 RETURN_IF_EMPTY_HANDLE_VALUE(
10771 isolate,
10772 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010773 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000010774 Handle<Object>(context->get(context_index), isolate),
10775 NONE,
10776 kNonStrictMode),
10777 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010778 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010779
10780 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010781}
10782
10783
10784// Create a plain JSObject which materializes the local scope for the specified
10785// frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010786static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010787 Isolate* isolate,
10788 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010789 FrameInspector* frame_inspector) {
10790 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010791 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010792 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010793
10794 // Allocate and initialize a JSObject with all the arguments, stack locals
10795 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010796 Handle<JSObject> local_scope =
10797 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010798
10799 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010800 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010801 Handle<Object> value(
10802 i < frame_inspector->GetParametersCount() ?
10803 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value());
10804
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010805 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010806 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010807 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010808 Handle<String>(scope_info->ParameterName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010809 value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010810 NONE,
10811 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010812 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010813 }
10814
10815 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010816 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010817 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010818 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010819 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010820 Handle<String>(scope_info->StackLocalName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010821 Handle<Object>(frame_inspector->GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010822 NONE,
10823 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010824 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010825 }
10826
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010827 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010828 // Third fill all context locals.
10829 Handle<Context> frame_context(Context::cast(frame->context()));
10830 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010831 if (!CopyContextLocalsToScopeObject(
10832 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010833 return Handle<JSObject>();
10834 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010835
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010836 // Finally copy any properties from the function context extension.
10837 // These will be variables introduced by eval.
10838 if (function_context->closure() == *function) {
10839 if (function_context->has_extension() &&
10840 !function_context->IsGlobalContext()) {
10841 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010842 bool threw = false;
10843 Handle<FixedArray> keys =
10844 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10845 if (threw) return Handle<JSObject>();
10846
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010847 for (int i = 0; i < keys->length(); i++) {
10848 // Names of variables introduced by eval are strings.
10849 ASSERT(keys->get(i)->IsString());
10850 Handle<String> key(String::cast(keys->get(i)));
10851 RETURN_IF_EMPTY_HANDLE_VALUE(
10852 isolate,
10853 SetProperty(local_scope,
10854 key,
10855 GetProperty(ext, key),
10856 NONE,
10857 kNonStrictMode),
10858 Handle<JSObject>());
10859 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010860 }
10861 }
10862 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010863
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010864 return local_scope;
10865}
10866
10867
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010868static Handle<JSObject> MaterializeLocalScope(
10869 Isolate* isolate,
10870 JavaScriptFrame* frame,
10871 int inlined_jsframe_index) {
10872 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
10873 return MaterializeLocalScopeWithFrameInspector(isolate,
10874 frame,
10875 &frame_inspector);
10876}
10877
10878
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010879// Create a plain JSObject which materializes the closure content for the
10880// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010881static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10882 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010883 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010884
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010885 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010886 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010887
ulan@chromium.org2efb9002012-01-19 15:36:35 +000010888 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010889 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010890 Handle<JSObject> closure_scope =
10891 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010892
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010893 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010894 if (!CopyContextLocalsToScopeObject(
10895 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010896 return Handle<JSObject>();
10897 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010898
10899 // Finally copy any properties from the function context extension. This will
10900 // be variables introduced by eval.
10901 if (context->has_extension()) {
10902 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010903 bool threw = false;
10904 Handle<FixedArray> keys =
10905 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10906 if (threw) return Handle<JSObject>();
10907
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010908 for (int i = 0; i < keys->length(); i++) {
10909 // Names of variables introduced by eval are strings.
10910 ASSERT(keys->get(i)->IsString());
10911 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010912 RETURN_IF_EMPTY_HANDLE_VALUE(
10913 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010914 SetProperty(closure_scope,
10915 key,
10916 GetProperty(ext, key),
10917 NONE,
10918 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010919 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010920 }
10921 }
10922
10923 return closure_scope;
10924}
10925
10926
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010927// Create a plain JSObject which materializes the scope for the specified
10928// catch context.
10929static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10930 Handle<Context> context) {
10931 ASSERT(context->IsCatchContext());
10932 Handle<String> name(String::cast(context->extension()));
10933 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10934 Handle<JSObject> catch_scope =
10935 isolate->factory()->NewJSObject(isolate->object_function());
10936 RETURN_IF_EMPTY_HANDLE_VALUE(
10937 isolate,
10938 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10939 Handle<JSObject>());
10940 return catch_scope;
10941}
10942
10943
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010944// Create a plain JSObject which materializes the block scope for the specified
10945// block context.
10946static Handle<JSObject> MaterializeBlockScope(
10947 Isolate* isolate,
10948 Handle<Context> context) {
10949 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010950 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010951
10952 // Allocate and initialize a JSObject with all the arguments, stack locals
10953 // heap locals and extension properties of the debugged function.
10954 Handle<JSObject> block_scope =
10955 isolate->factory()->NewJSObject(isolate->object_function());
10956
10957 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010958 if (!CopyContextLocalsToScopeObject(
10959 isolate, scope_info, context, block_scope)) {
10960 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010961 }
10962
10963 return block_scope;
10964}
10965
10966
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010967// Create a plain JSObject which materializes the module scope for the specified
10968// module context.
10969static Handle<JSObject> MaterializeModuleScope(
10970 Isolate* isolate,
10971 Handle<Context> context) {
10972 ASSERT(context->IsModuleContext());
10973 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
10974
10975 // Allocate and initialize a JSObject with all the members of the debugged
10976 // module.
10977 Handle<JSObject> module_scope =
10978 isolate->factory()->NewJSObject(isolate->object_function());
10979
10980 // Fill all context locals.
10981 if (!CopyContextLocalsToScopeObject(
10982 isolate, scope_info, context, module_scope)) {
10983 return Handle<JSObject>();
10984 }
10985
10986 return module_scope;
10987}
10988
10989
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010990// Iterate over the actual scopes visible from a stack frame. The iteration
10991// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010992// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010993// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010994class ScopeIterator {
10995 public:
10996 enum ScopeType {
10997 ScopeTypeGlobal = 0,
10998 ScopeTypeLocal,
10999 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011000 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011001 ScopeTypeCatch,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011002 ScopeTypeBlock,
11003 ScopeTypeModule
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011004 };
11005
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011006 ScopeIterator(Isolate* isolate,
11007 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011008 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011009 : isolate_(isolate),
11010 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011011 inlined_jsframe_index_(inlined_jsframe_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011012 function_(JSFunction::cast(frame->function())),
11013 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011014 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011015
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011016 // Catch the case when the debugger stops in an internal function.
11017 Handle<SharedFunctionInfo> shared_info(function_->shared());
11018 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11019 if (shared_info->script() == isolate->heap()->undefined_value()) {
11020 while (context_->closure() == *function_) {
11021 context_ = Handle<Context>(context_->previous(), isolate_);
11022 }
11023 return;
11024 }
11025
11026 // Get the debug info (create it if it does not exist).
11027 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
11028 // Return if ensuring debug info failed.
11029 return;
11030 }
11031 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11032
11033 // Find the break point where execution has stopped.
11034 BreakLocationIterator break_location_iterator(debug_info,
11035 ALL_BREAK_LOCATIONS);
11036 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
11037 if (break_location_iterator.IsExit()) {
11038 // We are within the return sequence. At the momemt it is not possible to
11039 // get a source position which is consistent with the current scope chain.
11040 // Thus all nested with, catch and block contexts are skipped and we only
11041 // provide the function scope.
11042 if (scope_info->HasContext()) {
11043 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11044 } else {
11045 while (context_->closure() == *function_) {
11046 context_ = Handle<Context>(context_->previous(), isolate_);
11047 }
11048 }
11049 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
11050 } else {
11051 // Reparse the code and analyze the scopes.
11052 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11053 Handle<Script> script(Script::cast(shared_info->script()));
11054 Scope* scope = NULL;
11055
11056 // Check whether we are in global, eval or function code.
11057 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11058 if (scope_info->Type() != FUNCTION_SCOPE) {
11059 // Global or eval code.
11060 CompilationInfo info(script);
11061 if (scope_info->Type() == GLOBAL_SCOPE) {
11062 info.MarkAsGlobal();
11063 } else {
11064 ASSERT(scope_info->Type() == EVAL_SCOPE);
11065 info.MarkAsEval();
11066 info.SetCallingContext(Handle<Context>(function_->context()));
11067 }
11068 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11069 scope = info.function()->scope();
11070 }
11071 } else {
11072 // Function code
11073 CompilationInfo info(shared_info);
11074 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11075 scope = info.function()->scope();
11076 }
11077 }
11078
11079 // Retrieve the scope chain for the current position.
11080 if (scope != NULL) {
11081 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11082 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11083 } else {
11084 // A failed reparse indicates that the preparser has diverged from the
11085 // parser or that the preparse data given to the initial parse has been
11086 // faulty. We fail in debug mode but in release mode we only provide the
11087 // information we get from the context chain but nothing about
11088 // completely stack allocated scopes or stack allocated locals.
11089 UNREACHABLE();
11090 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011091 }
11092 }
11093
11094 // More scopes?
11095 bool Done() { return context_.is_null(); }
11096
11097 // Move to the next scope.
11098 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011099 ScopeType scope_type = Type();
11100 if (scope_type == ScopeTypeGlobal) {
11101 // The global scope is always the last in the chain.
11102 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011103 context_ = Handle<Context>();
11104 return;
11105 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011106 if (nested_scope_chain_.is_empty()) {
11107 context_ = Handle<Context>(context_->previous(), isolate_);
11108 } else {
11109 if (nested_scope_chain_.last()->HasContext()) {
11110 ASSERT(context_->previous() != NULL);
11111 context_ = Handle<Context>(context_->previous(), isolate_);
11112 }
11113 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011114 }
11115 }
11116
11117 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011118 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011119 if (!nested_scope_chain_.is_empty()) {
11120 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11121 switch (scope_info->Type()) {
11122 case FUNCTION_SCOPE:
11123 ASSERT(context_->IsFunctionContext() ||
11124 !scope_info->HasContext());
11125 return ScopeTypeLocal;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011126 case MODULE_SCOPE:
11127 ASSERT(context_->IsModuleContext());
11128 return ScopeTypeModule;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011129 case GLOBAL_SCOPE:
11130 ASSERT(context_->IsGlobalContext());
11131 return ScopeTypeGlobal;
11132 case WITH_SCOPE:
11133 ASSERT(context_->IsWithContext());
11134 return ScopeTypeWith;
11135 case CATCH_SCOPE:
11136 ASSERT(context_->IsCatchContext());
11137 return ScopeTypeCatch;
11138 case BLOCK_SCOPE:
11139 ASSERT(!scope_info->HasContext() ||
11140 context_->IsBlockContext());
11141 return ScopeTypeBlock;
11142 case EVAL_SCOPE:
11143 UNREACHABLE();
11144 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011145 }
11146 if (context_->IsGlobalContext()) {
11147 ASSERT(context_->global()->IsGlobalObject());
11148 return ScopeTypeGlobal;
11149 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011150 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011151 return ScopeTypeClosure;
11152 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011153 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011154 return ScopeTypeCatch;
11155 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011156 if (context_->IsBlockContext()) {
11157 return ScopeTypeBlock;
11158 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011159 if (context_->IsModuleContext()) {
11160 return ScopeTypeModule;
11161 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011162 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011163 return ScopeTypeWith;
11164 }
11165
11166 // Return the JavaScript object with the content of the current scope.
11167 Handle<JSObject> ScopeObject() {
11168 switch (Type()) {
11169 case ScopeIterator::ScopeTypeGlobal:
11170 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011171 case ScopeIterator::ScopeTypeLocal:
11172 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011173 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011174 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011175 case ScopeIterator::ScopeTypeWith:
11176 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011177 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11178 case ScopeIterator::ScopeTypeCatch:
11179 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011180 case ScopeIterator::ScopeTypeClosure:
11181 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011182 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011183 case ScopeIterator::ScopeTypeBlock:
11184 return MaterializeBlockScope(isolate_, CurrentContext());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011185 case ScopeIterator::ScopeTypeModule:
11186 return MaterializeModuleScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011187 }
11188 UNREACHABLE();
11189 return Handle<JSObject>();
11190 }
11191
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011192 Handle<ScopeInfo> CurrentScopeInfo() {
11193 if (!nested_scope_chain_.is_empty()) {
11194 return nested_scope_chain_.last();
11195 } else if (context_->IsBlockContext()) {
11196 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11197 } else if (context_->IsFunctionContext()) {
11198 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11199 }
11200 return Handle<ScopeInfo>::null();
11201 }
11202
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011203 // Return the context for this scope. For the local context there might not
11204 // be an actual context.
11205 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011206 if (Type() == ScopeTypeGlobal ||
11207 nested_scope_chain_.is_empty()) {
11208 return context_;
11209 } else if (nested_scope_chain_.last()->HasContext()) {
11210 return context_;
11211 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011212 return Handle<Context>();
11213 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011214 }
11215
11216#ifdef DEBUG
11217 // Debug print of the content of the current scope.
11218 void DebugPrint() {
11219 switch (Type()) {
11220 case ScopeIterator::ScopeTypeGlobal:
11221 PrintF("Global:\n");
11222 CurrentContext()->Print();
11223 break;
11224
11225 case ScopeIterator::ScopeTypeLocal: {
11226 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011227 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011228 if (!CurrentContext().is_null()) {
11229 CurrentContext()->Print();
11230 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011231 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011232 if (extension->IsJSContextExtensionObject()) {
11233 extension->Print();
11234 }
11235 }
11236 }
11237 break;
11238 }
11239
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011240 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011241 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011242 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011243 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011244
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011245 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011246 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011247 CurrentContext()->extension()->Print();
11248 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011249 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011250
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011251 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011252 PrintF("Closure:\n");
11253 CurrentContext()->Print();
11254 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011255 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011256 if (extension->IsJSContextExtensionObject()) {
11257 extension->Print();
11258 }
11259 }
11260 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011261
11262 default:
11263 UNREACHABLE();
11264 }
11265 PrintF("\n");
11266 }
11267#endif
11268
11269 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011270 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011271 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011272 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011273 Handle<JSFunction> function_;
11274 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011275 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011276
11277 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11278};
11279
11280
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011281RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011282 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011283 ASSERT(args.length() == 2);
11284
11285 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011286 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011287 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11288 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011289 if (!maybe_check->ToObject(&check)) return maybe_check;
11290 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011291 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011292
11293 // Get the frame where the debugging is performed.
11294 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011295 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011296 JavaScriptFrame* frame = it.frame();
11297
11298 // Count the visible scopes.
11299 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011300 for (ScopeIterator it(isolate, frame, 0);
11301 !it.Done();
11302 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011303 n++;
11304 }
11305
11306 return Smi::FromInt(n);
11307}
11308
11309
11310static const int kScopeDetailsTypeIndex = 0;
11311static const int kScopeDetailsObjectIndex = 1;
11312static const int kScopeDetailsSize = 2;
11313
11314// Return an array with scope details
11315// args[0]: number: break id
11316// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011317// args[2]: number: inlined frame index
11318// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011319//
11320// The array returned contains the following information:
11321// 0: Scope type
11322// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011323RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011324 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011325 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011326
11327 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011328 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011329 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11330 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011331 if (!maybe_check->ToObject(&check)) return maybe_check;
11332 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011333 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011334 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011335 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011336
11337 // Get the frame where the debugging is performed.
11338 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011339 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011340 JavaScriptFrame* frame = frame_it.frame();
11341
11342 // Find the requested scope.
11343 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011344 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011345 for (; !it.Done() && n < index; it.Next()) {
11346 n++;
11347 }
11348 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011349 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011350 }
11351
11352 // Calculate the size of the result.
11353 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011354 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011355
11356 // Fill in scope details.
11357 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011358 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011359 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011360 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011361
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011362 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011363}
11364
11365
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011366RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011367 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011368 ASSERT(args.length() == 0);
11369
11370#ifdef DEBUG
11371 // Print the scopes for the top frame.
11372 StackFrameLocator locator;
11373 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011374 for (ScopeIterator it(isolate, frame, 0);
11375 !it.Done();
11376 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011377 it.DebugPrint();
11378 }
11379#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011380 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011381}
11382
11383
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011384RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011385 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011386 ASSERT(args.length() == 1);
11387
11388 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011389 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011390 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11391 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011392 if (!maybe_result->ToObject(&result)) return maybe_result;
11393 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011394
11395 // Count all archived V8 threads.
11396 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011397 for (ThreadState* thread =
11398 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011399 thread != NULL;
11400 thread = thread->Next()) {
11401 n++;
11402 }
11403
11404 // Total number of threads is current thread and archived threads.
11405 return Smi::FromInt(n + 1);
11406}
11407
11408
11409static const int kThreadDetailsCurrentThreadIndex = 0;
11410static const int kThreadDetailsThreadIdIndex = 1;
11411static const int kThreadDetailsSize = 2;
11412
11413// Return an array with thread details
11414// args[0]: number: break id
11415// args[1]: number: thread index
11416//
11417// The array returned contains the following information:
11418// 0: Is current thread?
11419// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011420RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011421 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011422 ASSERT(args.length() == 2);
11423
11424 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011425 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011426 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11427 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011428 if (!maybe_check->ToObject(&check)) return maybe_check;
11429 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011430 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11431
11432 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011433 Handle<FixedArray> details =
11434 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011435
11436 // Thread index 0 is current thread.
11437 if (index == 0) {
11438 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011439 details->set(kThreadDetailsCurrentThreadIndex,
11440 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011441 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011442 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011443 } else {
11444 // Find the thread with the requested index.
11445 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011446 ThreadState* thread =
11447 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011448 while (index != n && thread != NULL) {
11449 thread = thread->Next();
11450 n++;
11451 }
11452 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011453 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011454 }
11455
11456 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011457 details->set(kThreadDetailsCurrentThreadIndex,
11458 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011459 details->set(kThreadDetailsThreadIdIndex,
11460 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011461 }
11462
11463 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011464 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011465}
11466
11467
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011468// Sets the disable break state
11469// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011470RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011471 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011472 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011473 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011474 isolate->debug()->set_disable_break(disable_break);
11475 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011476}
11477
11478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011479RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011480 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011481 ASSERT(args.length() == 1);
11482
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011483 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011484 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011485 // Find the number of break points
11486 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011487 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011488 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011489 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011490 Handle<FixedArray>::cast(break_locations));
11491}
11492
11493
11494// Set a break point in a function
11495// args[0]: function
11496// args[1]: number: break source position (within the function source)
11497// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011498RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011499 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011500 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011501 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011502 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011503 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11504 RUNTIME_ASSERT(source_position >= 0);
11505 Handle<Object> break_point_object_arg = args.at<Object>(2);
11506
11507 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011508 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11509 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011510
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011511 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011512}
11513
11514
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011515Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11516 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011517 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011518 // Iterate the heap looking for SharedFunctionInfo generated from the
11519 // script. The inner most SharedFunctionInfo containing the source position
11520 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011521 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011522 // which is found is not compiled it is compiled and the heap is iterated
11523 // again as the compilation might create inner functions from the newly
11524 // compiled function and the actual requested break point might be in one of
11525 // these functions.
11526 bool done = false;
11527 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011528 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011529 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011530 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011531 { // Extra scope for iterator and no-allocation.
11532 isolate->heap()->EnsureHeapIsIterable();
11533 AssertNoAllocation no_alloc_during_heap_iteration;
11534 HeapIterator iterator;
11535 for (HeapObject* obj = iterator.next();
11536 obj != NULL; obj = iterator.next()) {
11537 if (obj->IsSharedFunctionInfo()) {
11538 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11539 if (shared->script() == *script) {
11540 // If the SharedFunctionInfo found has the requested script data and
11541 // contains the source position it is a candidate.
11542 int start_position = shared->function_token_position();
11543 if (start_position == RelocInfo::kNoPosition) {
11544 start_position = shared->start_position();
11545 }
11546 if (start_position <= position &&
11547 position <= shared->end_position()) {
11548 // If there is no candidate or this function is within the current
11549 // candidate this is the new candidate.
11550 if (target.is_null()) {
11551 target_start_position = start_position;
11552 target = shared;
11553 } else {
11554 if (target_start_position == start_position &&
11555 shared->end_position() == target->end_position()) {
11556 // If a top-level function contain only one function
11557 // declartion the source for the top-level and the
11558 // function is the same. In that case prefer the non
11559 // top-level function.
11560 if (!shared->is_toplevel()) {
11561 target_start_position = start_position;
11562 target = shared;
11563 }
11564 } else if (target_start_position <= start_position &&
11565 shared->end_position() <= target->end_position()) {
11566 // This containment check includes equality as a function
11567 // inside a top-level function can share either start or end
11568 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011569 target_start_position = start_position;
11570 target = shared;
11571 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011572 }
11573 }
11574 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011575 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011576 } // End for loop.
11577 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011578
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011579 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011580 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011581 }
11582
11583 // If the candidate found is compiled we are done. NOTE: when lazy
11584 // compilation of inner functions is introduced some additional checking
11585 // needs to be done here to compile inner functions.
11586 done = target->is_compiled();
11587 if (!done) {
11588 // If the candidate is not compiled compile it to reveal any inner
11589 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011590 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011591 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011592 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011593
11594 return *target;
11595}
11596
11597
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011598// Changes the state of a break point in a script and returns source position
11599// where break point was set. NOTE: Regarding performance see the NOTE for
11600// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011601// args[0]: script to set break point in
11602// args[1]: number: break source position (within the script source)
11603// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011604RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011605 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011606 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011607 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011608 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11609 RUNTIME_ASSERT(source_position >= 0);
11610 Handle<Object> break_point_object_arg = args.at<Object>(2);
11611
11612 // Get the script from the script wrapper.
11613 RUNTIME_ASSERT(wrapper->value()->IsScript());
11614 Handle<Script> script(Script::cast(wrapper->value()));
11615
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011616 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011617 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011618 if (!result->IsUndefined()) {
11619 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11620 // Find position within function. The script position might be before the
11621 // source position of the first function.
11622 int position;
11623 if (shared->start_position() > source_position) {
11624 position = 0;
11625 } else {
11626 position = source_position - shared->start_position();
11627 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011628 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011629 position += shared->start_position();
11630 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011631 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011632 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011633}
11634
11635
11636// Clear a break point
11637// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011638RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011639 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011640 ASSERT(args.length() == 1);
11641 Handle<Object> break_point_object_arg = args.at<Object>(0);
11642
11643 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011644 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011645
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011646 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011647}
11648
11649
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011650// Change the state of break on exceptions.
11651// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11652// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011653RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011654 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011655 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011656 RUNTIME_ASSERT(args[0]->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011657 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011658
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011659 // If the number doesn't match an enum value, the ChangeBreakOnException
11660 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011661 ExceptionBreakType type =
11662 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011663 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011664 isolate->debug()->ChangeBreakOnException(type, enable);
11665 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011666}
11667
11668
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011669// Returns the state of break on exceptions
11670// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011671RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011672 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011673 ASSERT(args.length() == 1);
11674 RUNTIME_ASSERT(args[0]->IsNumber());
11675
11676 ExceptionBreakType type =
11677 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011678 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011679 return Smi::FromInt(result);
11680}
11681
11682
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011683// Prepare for stepping
11684// args[0]: break id for checking execution state
11685// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011686// args[2]: number of times to perform the step, for step out it is the number
11687// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011688RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011689 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011690 ASSERT(args.length() == 3);
11691 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011692 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011693 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11694 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011695 if (!maybe_check->ToObject(&check)) return maybe_check;
11696 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011697 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011698 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011699 }
11700
11701 // Get the step action and check validity.
11702 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11703 if (step_action != StepIn &&
11704 step_action != StepNext &&
11705 step_action != StepOut &&
11706 step_action != StepInMin &&
11707 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011708 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011709 }
11710
11711 // Get the number of steps.
11712 int step_count = NumberToInt32(args[2]);
11713 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011714 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011715 }
11716
ager@chromium.orga1645e22009-09-09 19:27:10 +000011717 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011718 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011719
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011720 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011721 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11722 step_count);
11723 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011724}
11725
11726
11727// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011728RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011729 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011730 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011731 isolate->debug()->ClearStepping();
11732 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011733}
11734
11735
11736// Creates a copy of the with context chain. The copy of the context chain is
11737// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011738static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11739 Handle<JSFunction> function,
11740 Handle<Context> base,
11741 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011742 int inlined_jsframe_index) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011743 HandleScope scope(isolate);
11744 List<Handle<ScopeInfo> > scope_chain;
11745 List<Handle<Context> > context_chain;
11746
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011747 ScopeIterator it(isolate, frame, inlined_jsframe_index);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011748 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11749 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11750 ASSERT(!it.Done());
11751 scope_chain.Add(it.CurrentScopeInfo());
11752 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011753 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011754
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011755 // At the end of the chain. Return the base context to link to.
11756 Handle<Context> context = base;
11757
11758 // Iteratively copy and or materialize the nested contexts.
11759 while (!scope_chain.is_empty()) {
11760 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
11761 Handle<Context> current = context_chain.RemoveLast();
11762 ASSERT(!(scope_info->HasContext() & current.is_null()));
11763
11764 if (scope_info->Type() == CATCH_SCOPE) {
11765 Handle<String> name(String::cast(current->extension()));
11766 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11767 context =
11768 isolate->factory()->NewCatchContext(function,
11769 context,
11770 name,
11771 thrown_object);
11772 } else if (scope_info->Type() == BLOCK_SCOPE) {
11773 // Materialize the contents of the block scope into a JSObject.
11774 Handle<JSObject> block_scope_object =
11775 MaterializeBlockScope(isolate, current);
11776 if (block_scope_object.is_null()) {
11777 return Handle<Context>::null();
11778 }
11779 // Allocate a new function context for the debug evaluation and set the
11780 // extension object.
11781 Handle<Context> new_context =
11782 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11783 function);
11784 new_context->set_extension(*block_scope_object);
11785 new_context->set_previous(*context);
11786 context = new_context;
11787 } else {
11788 ASSERT(scope_info->Type() == WITH_SCOPE);
11789 ASSERT(current->IsWithContext());
11790 Handle<JSObject> extension(JSObject::cast(current->extension()));
11791 context =
11792 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000011793 }
erikcorry0ad885c2011-11-21 13:51:57 +000011794 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011795
11796 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011797}
11798
11799
11800// Helper function to find or create the arguments object for
11801// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011802static Handle<Object> GetArgumentsObject(Isolate* isolate,
11803 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011804 FrameInspector* frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011805 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011806 Handle<Context> function_context) {
11807 // Try to find the value of 'arguments' to pass as parameter. If it is not
11808 // found (that is the debugged function does not reference 'arguments' and
11809 // does not support eval) then create an 'arguments' object.
11810 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011811 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011812 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011813 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011814 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011815 }
11816 }
11817
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011818 if (scope_info->HasHeapAllocatedLocals()) {
11819 VariableMode mode;
11820 InitializationFlag init_flag;
11821 index = scope_info->ContextSlotIndex(
11822 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011823 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011824 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011825 }
11826 }
11827
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011828 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
11829 int length = frame_inspector->GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011830 Handle<JSObject> arguments =
11831 isolate->factory()->NewArgumentsObject(function, length);
11832 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011833
11834 AssertNoAllocation no_gc;
11835 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011836 for (int i = 0; i < length; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011837 array->set(i, frame_inspector->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011838 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011839 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011840 return arguments;
11841}
11842
11843
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011844static const char kSourceStr[] =
11845 "(function(arguments,__source__){return eval(__source__);})";
11846
11847
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011848// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011849// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011850// extension part has all the parameters and locals of the function on the
11851// stack frame. A function which calls eval with the code to evaluate is then
11852// compiled in this context and called in this context. As this context
11853// replaces the context of the function on the stack frame a new (empty)
11854// function is created as well to be used as the closure for the context.
11855// This function and the context acts as replacements for the function on the
11856// stack frame presenting the same view of the values of parameters and
11857// local variables as if the piece of JavaScript was evaluated at the point
11858// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011859RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011860 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011861
11862 // Check the execution state and decode arguments frame and source to be
11863 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011864 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011865 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011866 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11867 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011868 if (!maybe_check_result->ToObject(&check_result)) {
11869 return maybe_check_result;
11870 }
11871 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011872 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011873 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011874 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
11875 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011876 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011877
11878 // Handle the processing of break.
11879 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011880
11881 // Get the frame where the debugging is performed.
11882 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011883 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011884 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011885 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11886 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011887 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011888
11889 // Traverse the saved contexts chain to find the active context for the
11890 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011891 SaveContext* save = FindSavedContextForFrame(isolate, frame);
11892
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011893 SaveContext savex(isolate);
11894 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011895
11896 // Create the (empty) function replacing the function on the stack frame for
11897 // the purpose of evaluating in the context created below. It is important
11898 // that this function does not describe any parameters and local variables
11899 // in the context. If it does then this will cause problems with the lookup
11900 // in Context::Lookup, where context slots for parameters and local variables
11901 // are looked at before the extension object.
11902 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011903 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11904 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011905 go_between->set_context(function->context());
11906#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011907 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
11908 ASSERT(go_between_scope_info->ParameterCount() == 0);
11909 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011910#endif
11911
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011912 // Materialize the content of the local scope into a JSObject.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011913 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
11914 isolate, frame, &frame_inspector);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011915 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011916
11917 // Allocate a new context for the debug evaluation and set the extension
11918 // object build.
11919 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011920 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11921 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011922 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011923 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011924 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011925 Handle<Context> function_context;
11926 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011927 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011928 function_context = Handle<Context>(frame_context->declaration_context());
11929 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011930 context = CopyNestedScopeContextChain(isolate,
11931 go_between,
11932 context,
11933 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011934 inlined_jsframe_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011935
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011936 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011937 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011938 context =
11939 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011940 }
11941
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011942 // Wrap the evaluation statement in a new function compiled in the newly
11943 // created context. The function has one parameter which has to be called
11944 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011945 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011946 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011947
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011948 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011949 isolate->factory()->NewStringFromAscii(
11950 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011951
11952 // Currently, the eval code will be executed in non-strict mode,
11953 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011954 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011955 Compiler::CompileEval(function_source,
11956 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011957 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011958 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011959 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011960 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011961 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011962 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011963
11964 // Invoke the result of the compilation to get the evaluation function.
11965 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011966 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011967 Handle<Object> evaluation_function =
11968 Execution::Call(compiled_function, receiver, 0, NULL,
11969 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011970 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011971
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011972 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011973 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011974 &frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011975 scope_info,
11976 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011977
11978 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011979 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011980 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011981 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
11982 receiver,
11983 ARRAY_SIZE(argv),
11984 argv,
11985 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011986 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011987
11988 // Skip the global proxy as it has no properties and always delegates to the
11989 // real global object.
11990 if (result->IsJSGlobalProxy()) {
11991 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11992 }
11993
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011994 return *result;
11995}
11996
11997
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011998RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011999 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012000
12001 // Check the execution state and decode arguments frame and source to be
12002 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012003 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012004 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012005 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12006 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012007 if (!maybe_check_result->ToObject(&check_result)) {
12008 return maybe_check_result;
12009 }
12010 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012011 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
12012 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012013 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012014
12015 // Handle the processing of break.
12016 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012017
12018 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012019 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012020 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012021 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012022 top = top->prev();
12023 }
12024 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012025 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012026 }
12027
12028 // Get the global context now set to the top context from before the
12029 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012030 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012031
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012032 bool is_global = true;
12033
12034 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000012035 // Create a new with context with the additional context information between
12036 // the context of the debugged function and the eval code to be executed.
12037 context = isolate->factory()->NewWithContext(
12038 Handle<JSFunction>(context->closure()),
12039 context,
12040 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012041 is_global = false;
12042 }
12043
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012044 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012045 // Currently, the eval code will be executed in non-strict mode,
12046 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012047 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012048 Compiler::CompileEval(source,
12049 context,
12050 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012051 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012052 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012053 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012054 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012055 Handle<JSFunction>(
12056 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12057 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012058
12059 // Invoke the result of the compilation to get the evaluation function.
12060 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012061 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012062 Handle<Object> result =
12063 Execution::Call(compiled_function, receiver, 0, NULL,
12064 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012065 // Clear the oneshot breakpoints so that the debugger does not step further.
12066 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012067 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012068 return *result;
12069}
12070
12071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012072RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012073 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012074 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012075
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012076 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012077 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012078
12079 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012080 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012081 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12082 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12083 // because using
12084 // instances->set(i, *GetScriptWrapper(script))
12085 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012086 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012087 Handle<JSValue> wrapper = GetScriptWrapper(script);
12088 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012089 }
12090
12091 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012092 Handle<JSObject> result =
12093 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012094 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012095 return *result;
12096}
12097
12098
12099// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012100static int DebugReferencedBy(HeapIterator* iterator,
12101 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012102 Object* instance_filter, int max_references,
12103 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012104 JSFunction* arguments_function) {
12105 NoHandleAllocation ha;
12106 AssertNoAllocation no_alloc;
12107
12108 // Iterate the heap.
12109 int count = 0;
12110 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012111 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012112 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012113 (max_references == 0 || count < max_references)) {
12114 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012115 if (heap_obj->IsJSObject()) {
12116 // Skip context extension objects and argument arrays as these are
12117 // checked in the context of functions using them.
12118 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012119 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012120 obj->map()->constructor() == arguments_function) {
12121 continue;
12122 }
12123
12124 // Check if the JS object has a reference to the object looked for.
12125 if (obj->ReferencesObject(target)) {
12126 // Check instance filter if supplied. This is normally used to avoid
12127 // references from mirror objects (see Runtime_IsInPrototypeChain).
12128 if (!instance_filter->IsUndefined()) {
12129 Object* V = obj;
12130 while (true) {
12131 Object* prototype = V->GetPrototype();
12132 if (prototype->IsNull()) {
12133 break;
12134 }
12135 if (instance_filter == prototype) {
12136 obj = NULL; // Don't add this object.
12137 break;
12138 }
12139 V = prototype;
12140 }
12141 }
12142
12143 if (obj != NULL) {
12144 // Valid reference found add to instance array if supplied an update
12145 // count.
12146 if (instances != NULL && count < instances_size) {
12147 instances->set(count, obj);
12148 }
12149 last = obj;
12150 count++;
12151 }
12152 }
12153 }
12154 }
12155
12156 // Check for circular reference only. This can happen when the object is only
12157 // referenced from mirrors and has a circular reference in which case the
12158 // object is not really alive and would have been garbage collected if not
12159 // referenced from the mirror.
12160 if (count == 1 && last == target) {
12161 count = 0;
12162 }
12163
12164 // Return the number of referencing objects found.
12165 return count;
12166}
12167
12168
12169// Scan the heap for objects with direct references to an object
12170// args[0]: the object to find references to
12171// args[1]: constructor function for instances to exclude (Mirror)
12172// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012173RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012174 ASSERT(args.length() == 3);
12175
12176 // First perform a full GC in order to avoid references from dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012177 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12178 "%DebugReferencedBy");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012179 // The heap iterator reserves the right to do a GC to make the heap iterable.
12180 // Due to the GC above we know it won't need to do that, but it seems cleaner
12181 // to get the heap iterator constructed before we start having unprotected
12182 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012183
12184 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012185 CONVERT_ARG_CHECKED(JSObject, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012186 Object* instance_filter = args[1];
12187 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12188 instance_filter->IsJSObject());
12189 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12190 RUNTIME_ASSERT(max_references >= 0);
12191
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012192
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012193 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012194 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012195 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012196 JSFunction* arguments_function =
12197 JSFunction::cast(arguments_boilerplate->map()->constructor());
12198
12199 // Get the number of referencing objects.
12200 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012201 HeapIterator heap_iterator;
12202 count = DebugReferencedBy(&heap_iterator,
12203 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012204 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012205
12206 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012207 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012208 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012209 if (!maybe_object->ToObject(&object)) return maybe_object;
12210 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012211 FixedArray* instances = FixedArray::cast(object);
12212
12213 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012214 // AllocateFixedArray above does not make the heap non-iterable.
12215 ASSERT(HEAP->IsHeapIterable());
12216 HeapIterator heap_iterator2;
12217 count = DebugReferencedBy(&heap_iterator2,
12218 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012219 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012220
12221 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012222 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012223 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012224 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012225 if (!maybe_result->ToObject(&result)) return maybe_result;
12226 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012227}
12228
12229
12230// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012231static int DebugConstructedBy(HeapIterator* iterator,
12232 JSFunction* constructor,
12233 int max_references,
12234 FixedArray* instances,
12235 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012236 AssertNoAllocation no_alloc;
12237
12238 // Iterate the heap.
12239 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012240 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012241 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012242 (max_references == 0 || count < max_references)) {
12243 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012244 if (heap_obj->IsJSObject()) {
12245 JSObject* obj = JSObject::cast(heap_obj);
12246 if (obj->map()->constructor() == constructor) {
12247 // Valid reference found add to instance array if supplied an update
12248 // count.
12249 if (instances != NULL && count < instances_size) {
12250 instances->set(count, obj);
12251 }
12252 count++;
12253 }
12254 }
12255 }
12256
12257 // Return the number of referencing objects found.
12258 return count;
12259}
12260
12261
12262// Scan the heap for objects constructed by a specific function.
12263// args[0]: the constructor to find instances of
12264// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012265RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012266 ASSERT(args.length() == 2);
12267
12268 // First perform a full GC in order to avoid dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012269 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12270 "%DebugConstructedBy");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012271
12272 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012273 CONVERT_ARG_CHECKED(JSFunction, constructor, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012274 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12275 RUNTIME_ASSERT(max_references >= 0);
12276
12277 // Get the number of referencing objects.
12278 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012279 HeapIterator heap_iterator;
12280 count = DebugConstructedBy(&heap_iterator,
12281 constructor,
12282 max_references,
12283 NULL,
12284 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012285
12286 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012287 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012288 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012289 if (!maybe_object->ToObject(&object)) return maybe_object;
12290 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012291 FixedArray* instances = FixedArray::cast(object);
12292
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012293 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012294 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012295 HeapIterator heap_iterator2;
12296 count = DebugConstructedBy(&heap_iterator2,
12297 constructor,
12298 max_references,
12299 instances,
12300 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012301
12302 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012303 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012304 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12305 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012306 if (!maybe_result->ToObject(&result)) return maybe_result;
12307 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012308 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012309}
12310
12311
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012312// Find the effective prototype object as returned by __proto__.
12313// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012314RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012315 ASSERT(args.length() == 1);
12316
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012317 CONVERT_ARG_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012318
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012319 // Use the __proto__ accessor.
12320 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012321}
12322
12323
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000012324// Patches script source (should be called upon BeforeCompile event).
12325RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugSetScriptSource) {
12326 HandleScope scope(isolate);
12327 ASSERT(args.length() == 2);
12328
12329 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
12330 Handle<String> source(String::cast(args[1]));
12331
12332 RUNTIME_ASSERT(script_wrapper->value()->IsScript());
12333 Handle<Script> script(Script::cast(script_wrapper->value()));
12334
12335 int compilation_state = Smi::cast(script->compilation_state())->value();
12336 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
12337 script->set_source(*source);
12338
12339 return isolate->heap()->undefined_value();
12340}
12341
12342
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012343RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012344 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012345 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012346 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012347}
12348
12349
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012350RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012351#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012352 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012353 ASSERT(args.length() == 1);
12354 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012355 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012356 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012357 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012358 return Failure::Exception();
12359 }
12360 func->code()->PrintLn();
12361#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012362 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012363}
ager@chromium.org9085a012009-05-11 19:22:57 +000012364
12365
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012366RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012367#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012368 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012369 ASSERT(args.length() == 1);
12370 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012371 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012372 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012373 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012374 return Failure::Exception();
12375 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012376 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012377#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012378 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012379}
12380
12381
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012382RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012383 NoHandleAllocation ha;
12384 ASSERT(args.length() == 1);
12385
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012386 CONVERT_ARG_CHECKED(JSFunction, f, 0);
ager@chromium.org9085a012009-05-11 19:22:57 +000012387 return f->shared()->inferred_name();
12388}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012389
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012390
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012391static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12392 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012393 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012394 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012395 int counter = 0;
12396 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012397 for (HeapObject* obj = iterator->next();
12398 obj != NULL;
12399 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012400 ASSERT(obj != NULL);
12401 if (!obj->IsSharedFunctionInfo()) {
12402 continue;
12403 }
12404 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12405 if (shared->script() != script) {
12406 continue;
12407 }
12408 if (counter < buffer_size) {
12409 buffer->set(counter, shared);
12410 }
12411 counter++;
12412 }
12413 return counter;
12414}
12415
12416// For a script finds all SharedFunctionInfo's in the heap that points
12417// to this script. Returns JSArray of SharedFunctionInfo wrapped
12418// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012419RUNTIME_FUNCTION(MaybeObject*,
12420 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012421 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012422 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012423 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012424
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012425
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012426 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12427
12428 const int kBufferSize = 32;
12429
12430 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012431 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012432 int number;
12433 {
12434 isolate->heap()->EnsureHeapIsIterable();
12435 AssertNoAllocation no_allocations;
12436 HeapIterator heap_iterator;
12437 Script* scr = *script;
12438 FixedArray* arr = *array;
12439 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12440 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012441 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012442 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012443 isolate->heap()->EnsureHeapIsIterable();
12444 AssertNoAllocation no_allocations;
12445 HeapIterator heap_iterator;
12446 Script* scr = *script;
12447 FixedArray* arr = *array;
12448 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012449 }
12450
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012451 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012452 result->set_length(Smi::FromInt(number));
12453
12454 LiveEdit::WrapSharedFunctionInfos(result);
12455
12456 return *result;
12457}
12458
12459// For a script calculates compilation information about all its functions.
12460// The script source is explicitly specified by the second argument.
12461// The source of the actual script is not used, however it is important that
12462// all generated code keeps references to this particular instance of script.
12463// Returns a JSArray of compilation infos. The array is ordered so that
12464// each function with all its descendant is always stored in a continues range
12465// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012466RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012467 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012468 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012469 CONVERT_ARG_CHECKED(JSValue, script, 0);
12470 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012471 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12472
12473 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12474
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012475 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012476 return Failure::Exception();
12477 }
12478
12479 return result;
12480}
12481
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012482// Changes the source of the script to a new_source.
12483// If old_script_name is provided (i.e. is a String), also creates a copy of
12484// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012485RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012486 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012487 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012488 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
12489 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012490 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012491
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012492 RUNTIME_ASSERT(original_script_value->value()->IsScript());
12493 Handle<Script> original_script(Script::cast(original_script_value->value()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012494
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012495 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12496 new_source,
12497 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012498
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012499 if (old_script->IsScript()) {
12500 Handle<Script> script_handle(Script::cast(old_script));
12501 return *(GetScriptWrapper(script_handle));
12502 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012503 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012504 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012505}
12506
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012507
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012508RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012509 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012510 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012511 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012512 return LiveEdit::FunctionSourceUpdated(shared_info);
12513}
12514
12515
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012516// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012517RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012518 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012519 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012520 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
12521 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012522
ager@chromium.orgac091b72010-05-05 07:34:42 +000012523 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012524}
12525
12526// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012527RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012528 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012529 HandleScope scope(isolate);
12530 Handle<Object> function_object(args[0], isolate);
12531 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012532
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012533 if (function_object->IsJSValue()) {
12534 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12535 if (script_object->IsJSValue()) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012536 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
12537 Script* script = Script::cast(JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012538 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012539 }
12540
12541 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12542 } else {
12543 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12544 // and we check it in this function.
12545 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012546
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012547 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012548}
12549
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012550
12551// In a code of a parent function replaces original function as embedded object
12552// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012553RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012554 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012555 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012556
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012557 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
12558 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
12559 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012560
12561 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12562 subst_wrapper);
12563
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012564 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012565}
12566
12567
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012568// Updates positions of a shared function info (first parameter) according
12569// to script source change. Text change is described in second parameter as
12570// array of groups of 3 numbers:
12571// (change_begin, change_end, change_end_new_position).
12572// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012573RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012574 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012575 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012576 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12577 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012578
ager@chromium.orgac091b72010-05-05 07:34:42 +000012579 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012580}
12581
12582
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012583// For array of SharedFunctionInfo's (each wrapped in JSValue)
12584// checks that none of them have activations on stacks (of any thread).
12585// Returns array of the same length with corresponding results of
12586// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012587RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012588 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012589 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012590 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12591 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012592
ager@chromium.org357bf652010-04-12 11:30:10 +000012593 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012594}
12595
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012596// Compares 2 strings line-by-line, then token-wise and returns diff in form
12597// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12598// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012599RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012600 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012601 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012602 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
12603 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012604
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012605 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012606}
12607
12608
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012609// A testing entry. Returns statement position which is the closest to
12610// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012611RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012612 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012613 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012614 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012615 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12616
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012617 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012618
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012619 if (code->kind() != Code::FUNCTION &&
12620 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012621 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012622 }
12623
12624 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012625 int closest_pc = 0;
12626 int distance = kMaxInt;
12627 while (!it.done()) {
12628 int statement_position = static_cast<int>(it.rinfo()->data());
12629 // Check if this break point is closer that what was previously found.
12630 if (source_position <= statement_position &&
12631 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012632 closest_pc =
12633 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012634 distance = statement_position - source_position;
12635 // Check whether we can't get any closer.
12636 if (distance == 0) break;
12637 }
12638 it.next();
12639 }
12640
12641 return Smi::FromInt(closest_pc);
12642}
12643
12644
ager@chromium.org357bf652010-04-12 11:30:10 +000012645// Calls specified function with or without entering the debugger.
12646// This is used in unit tests to run code as if debugger is entered or simply
12647// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012648RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012649 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012650 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012651 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12652 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
ager@chromium.org357bf652010-04-12 11:30:10 +000012653
12654 Handle<Object> result;
12655 bool pending_exception;
12656 {
12657 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012658 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012659 &pending_exception);
12660 } else {
12661 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012662 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012663 &pending_exception);
12664 }
12665 }
12666 if (!pending_exception) {
12667 return *result;
12668 } else {
12669 return Failure::Exception();
12670 }
12671}
12672
12673
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012674// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012675RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012676 CONVERT_ARG_CHECKED(String, arg, 0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012677 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012678 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12679 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012680 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012681}
12682
12683
12684// Performs a GC.
12685// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012686RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000012687 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012688 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012689}
12690
12691
12692// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012693RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012694 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012695 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012696 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012697 }
12698 return Smi::FromInt(usage);
12699}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012700
12701
12702// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012703RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012704#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012705 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012706#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012707 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012708#endif
12709}
12710
12711
12712// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012713RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012714#ifdef LIVE_OBJECT_LIST
12715 return LiveObjectList::Capture();
12716#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012717 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012718#endif
12719}
12720
12721
12722// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012723RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012724#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012725 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012726 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012727 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012728#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012729 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012730#endif
12731}
12732
12733
12734// Generates the response to a debugger request for a dump of the objects
12735// contained in the difference between the captured live object lists
12736// specified by id1 and id2.
12737// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12738// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012739RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012740#ifdef LIVE_OBJECT_LIST
12741 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012742 CONVERT_SMI_ARG_CHECKED(id1, 0);
12743 CONVERT_SMI_ARG_CHECKED(id2, 1);
12744 CONVERT_SMI_ARG_CHECKED(start, 2);
12745 CONVERT_SMI_ARG_CHECKED(count, 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012746 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012747 EnterDebugger enter_debugger;
12748 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12749#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012750 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012751#endif
12752}
12753
12754
12755// Gets the specified object as requested by the debugger.
12756// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012757RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012758#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012759 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012760 Object* result = LiveObjectList::GetObj(obj_id);
12761 return result;
12762#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012763 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012764#endif
12765}
12766
12767
12768// Gets the obj id for the specified address if valid.
12769// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012770RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012771#ifdef LIVE_OBJECT_LIST
12772 HandleScope scope;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012773 CONVERT_ARG_HANDLE_CHECKED(String, address, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012774 Object* result = LiveObjectList::GetObjId(address);
12775 return result;
12776#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012777 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012778#endif
12779}
12780
12781
12782// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012783RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012784#ifdef LIVE_OBJECT_LIST
12785 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012786 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012787 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12788 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12789 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12790 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012791 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 5);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012792
12793 Handle<JSObject> instance_filter;
12794 if (args[1]->IsJSObject()) {
12795 instance_filter = args.at<JSObject>(1);
12796 }
12797 bool verbose = false;
12798 if (args[2]->IsBoolean()) {
12799 verbose = args[2]->IsTrue();
12800 }
12801 int start = 0;
12802 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012803 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012804 }
12805 int limit = Smi::kMaxValue;
12806 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012807 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012808 }
12809
12810 return LiveObjectList::GetObjRetainers(obj_id,
12811 instance_filter,
12812 verbose,
12813 start,
12814 limit,
12815 filter_obj);
12816#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012817 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012818#endif
12819}
12820
12821
12822// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012823RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012824#ifdef LIVE_OBJECT_LIST
12825 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012826 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12827 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012828 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12829
12830 Handle<JSObject> instance_filter;
12831 if (args[2]->IsJSObject()) {
12832 instance_filter = args.at<JSObject>(2);
12833 }
12834
12835 Object* result =
12836 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12837 return result;
12838#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012839 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012840#endif
12841}
12842
12843
12844// Generates the response to a debugger request for a list of all
12845// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012846RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012847#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012848 CONVERT_SMI_ARG_CHECKED(start, 0);
12849 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012850 return LiveObjectList::Info(start, count);
12851#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012852 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012853#endif
12854}
12855
12856
12857// Gets a dump of the specified object as requested by the debugger.
12858// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012859RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012860#ifdef LIVE_OBJECT_LIST
12861 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012862 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012863 Object* result = LiveObjectList::PrintObj(obj_id);
12864 return result;
12865#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012866 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012867#endif
12868}
12869
12870
12871// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012872RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012873#ifdef LIVE_OBJECT_LIST
12874 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012875 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012876#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012877 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012878#endif
12879}
12880
12881
12882// Generates the response to a debugger request for a summary of the types
12883// of objects in the difference between the captured live object lists
12884// specified by id1 and id2.
12885// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12886// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012887RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012888#ifdef LIVE_OBJECT_LIST
12889 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012890 CONVERT_SMI_ARG_CHECKED(id1, 0);
12891 CONVERT_SMI_ARG_CHECKED(id2, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012892 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012893
12894 EnterDebugger enter_debugger;
12895 return LiveObjectList::Summarize(id1, id2, filter_obj);
12896#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012897 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012898#endif
12899}
12900
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012901#endif // ENABLE_DEBUGGER_SUPPORT
12902
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012903
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012904RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012905 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012906 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012907 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012908}
12909
12910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012911RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012912 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012913 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012914 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012915}
12916
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012917
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012918// Finds the script object from the script data. NOTE: This operation uses
12919// heap traversal to find the function generated for the source position
12920// for the requested break point. For lazily compiled functions several heap
12921// traversals might be required rendering this operation as a rather slow
12922// operation. However for setting break points which is normally done through
12923// some kind of user interaction the performance is not crucial.
12924static Handle<Object> Runtime_GetScriptFromScriptName(
12925 Handle<String> script_name) {
12926 // Scan the heap for Script objects to find the script with the requested
12927 // script data.
12928 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012929 script_name->GetHeap()->EnsureHeapIsIterable();
12930 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012931 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012932 HeapObject* obj = NULL;
12933 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012934 // If a script is found check if it has the script data requested.
12935 if (obj->IsScript()) {
12936 if (Script::cast(obj)->name()->IsString()) {
12937 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12938 script = Handle<Script>(Script::cast(obj));
12939 }
12940 }
12941 }
12942 }
12943
12944 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012945 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012946
12947 // Return the script found.
12948 return GetScriptWrapper(script);
12949}
12950
12951
12952// Get the script object from script data. NOTE: Regarding performance
12953// see the NOTE for GetScriptFromScriptData.
12954// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012955RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012956 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012957
12958 ASSERT(args.length() == 1);
12959
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012960 CONVERT_ARG_CHECKED(String, script_name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012961
12962 // Find the requested script.
12963 Handle<Object> result =
12964 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12965 return *result;
12966}
12967
12968
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012969// Determines whether the given stack frame should be displayed in
12970// a stack trace. The caller is the error constructor that asked
12971// for the stack trace to be collected. The first time a construct
12972// call to this function is encountered it is skipped. The seen_caller
12973// in/out parameter is used to remember if the caller has been seen
12974// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012975static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12976 Object* caller,
12977 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012978 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012979 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012980 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012981 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012982 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12983 Object* raw_fun = frame->function();
12984 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012985 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012986 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012987 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012988 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012989 *seen_caller = true;
12990 return false;
12991 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012992 // Skip all frames until we've seen the caller.
12993 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012994 // Also, skip non-visible built-in functions and any call with the builtins
12995 // object as receiver, so as to not reveal either the builtins object or
12996 // an internal function.
12997 // The --builtins-in-stack-traces command line flag allows including
12998 // internal call sites in the stack trace for debugging purposes.
12999 if (!FLAG_builtins_in_stack_traces) {
13000 JSFunction* fun = JSFunction::cast(raw_fun);
13001 if (frame->receiver()->IsJSBuiltinsObject() ||
13002 (fun->IsBuiltin() && !fun->shared()->native())) {
13003 return false;
13004 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013005 }
13006 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013007}
13008
13009
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013010// Collect the raw data for a stack trace. Returns an array of 4
13011// element segments each containing a receiver, function, code and
13012// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013013RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013014 ASSERT_EQ(args.length(), 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013015 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013016 Handle<Object> caller = args.at<Object>(1);
13017 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013018
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013019 HandleScope scope(isolate);
13020 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013021
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013022 limit = Max(limit, 0); // Ensure that limit is not negative.
13023 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013024 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013025 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013026
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013027 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013028 // If the caller parameter is a function we skip frames until we're
13029 // under it before starting to collect.
13030 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013031 int cursor = 0;
13032 int frames_seen = 0;
13033 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013034 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013035 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013036 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013037 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013038 // Set initial size to the maximum inlining level + 1 for the outermost
13039 // function.
13040 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013041 frame->Summarize(&frames);
13042 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013043 if (cursor + 4 > elements->length()) {
13044 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13045 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013046 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013047 for (int i = 0; i < cursor; i++) {
13048 new_elements->set(i, elements->get(i));
13049 }
13050 elements = new_elements;
13051 }
13052 ASSERT(cursor + 4 <= elements->length());
13053
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013054 Handle<Object> recv = frames[i].receiver();
13055 Handle<JSFunction> fun = frames[i].function();
13056 Handle<Code> code = frames[i].code();
13057 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013058 elements->set(cursor++, *recv);
13059 elements->set(cursor++, *fun);
13060 elements->set(cursor++, *code);
13061 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013062 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013063 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013064 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013065 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013066 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013067 // Capture and attach a more detailed stack trace if necessary.
13068 isolate->CaptureAndSetCurrentStackTraceFor(error_object);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013069 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013070 return *result;
13071}
13072
13073
ager@chromium.org3811b432009-10-28 14:53:37 +000013074// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013075RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013076 ASSERT_EQ(args.length(), 0);
13077
13078 NoHandleAllocation ha;
13079
13080 const char* version_string = v8::V8::GetVersion();
13081
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013082 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13083 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013084}
13085
13086
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013087RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013088 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013089 OS::PrintError("abort: %s\n",
13090 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013091 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013092 OS::Abort();
13093 UNREACHABLE();
13094 return NULL;
13095}
13096
13097
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013098RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013099 // This is only called from codegen, so checks might be more lax.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013100 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013101 Object* key = args[1];
13102
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013103 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013104 Object* o = cache->get(finger_index);
13105 if (o == key) {
13106 // The fastest case: hit the same place again.
13107 return cache->get(finger_index + 1);
13108 }
13109
13110 for (int i = finger_index - 2;
13111 i >= JSFunctionResultCache::kEntriesIndex;
13112 i -= 2) {
13113 o = cache->get(i);
13114 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013115 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013116 return cache->get(i + 1);
13117 }
13118 }
13119
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013120 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013121 ASSERT(size <= cache->length());
13122
13123 for (int i = size - 2; i > finger_index; i -= 2) {
13124 o = cache->get(i);
13125 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013126 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013127 return cache->get(i + 1);
13128 }
13129 }
13130
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013131 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013132 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013133
13134 Handle<JSFunctionResultCache> cache_handle(cache);
13135 Handle<Object> key_handle(key);
13136 Handle<Object> value;
13137 {
13138 Handle<JSFunction> factory(JSFunction::cast(
13139 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13140 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013141 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013142 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013143 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013144 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013145 value = Execution::Call(factory,
13146 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013147 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013148 argv,
13149 &pending_exception);
13150 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013151 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013152
13153#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013154 if (FLAG_verify_heap) {
13155 cache_handle->JSFunctionResultCacheVerify();
13156 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013157#endif
13158
13159 // Function invocation may have cleared the cache. Reread all the data.
13160 finger_index = cache_handle->finger_index();
13161 size = cache_handle->size();
13162
13163 // If we have spare room, put new data into it, otherwise evict post finger
13164 // entry which is likely to be the least recently used.
13165 int index = -1;
13166 if (size < cache_handle->length()) {
13167 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13168 index = size;
13169 } else {
13170 index = finger_index + JSFunctionResultCache::kEntrySize;
13171 if (index == cache_handle->length()) {
13172 index = JSFunctionResultCache::kEntriesIndex;
13173 }
13174 }
13175
13176 ASSERT(index % 2 == 0);
13177 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13178 ASSERT(index < cache_handle->length());
13179
13180 cache_handle->set(index, *key_handle);
13181 cache_handle->set(index + 1, *value);
13182 cache_handle->set_finger_index(index);
13183
13184#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013185 if (FLAG_verify_heap) {
13186 cache_handle->JSFunctionResultCacheVerify();
13187 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013188#endif
13189
13190 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013191}
13192
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013194RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013195 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013196 CONVERT_ARG_HANDLE_CHECKED(String, type, 0);
13197 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013198 return *isolate->factory()->NewJSMessageObject(
13199 type,
13200 arguments,
13201 0,
13202 0,
13203 isolate->factory()->undefined_value(),
13204 isolate->factory()->undefined_value(),
13205 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013206}
13207
13208
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013209RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013210 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013211 return message->type();
13212}
13213
13214
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013215RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013216 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013217 return message->arguments();
13218}
13219
13220
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013221RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013222 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013223 return Smi::FromInt(message->start_position());
13224}
13225
13226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013227RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013228 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013229 return message->script();
13230}
13231
13232
kasper.lund44510672008-07-25 07:37:58 +000013233#ifdef DEBUG
13234// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13235// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013236RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013237 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013238 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013239#define COUNT_ENTRY(Name, argc, ressize) + 1
13240 int entry_count = 0
13241 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13242 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13243 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13244#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013245 Factory* factory = isolate->factory();
13246 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013247 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013248 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013249#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013250 { \
13251 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013252 Handle<String> name; \
13253 /* Inline runtime functions have an underscore in front of the name. */ \
13254 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013255 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013256 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13257 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013258 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013259 Vector<const char>(#Name, StrLength(#Name))); \
13260 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013261 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013262 pair_elements->set(0, *name); \
13263 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013264 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013265 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013266 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013267 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013268 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013269 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013270 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013271 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013272#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013273 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013274 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013275 return *result;
13276}
kasper.lund44510672008-07-25 07:37:58 +000013277#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013278
13279
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013280RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013281 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013282 CONVERT_ARG_CHECKED(String, format, 0);
13283 CONVERT_ARG_CHECKED(JSArray, elms, 1);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013284 String::FlatContent format_content = format->GetFlatContent();
13285 RUNTIME_ASSERT(format_content.IsAscii());
13286 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013287 LOGGER->LogRuntime(chars, elms);
13288 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013289}
13290
13291
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013292RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013293 UNREACHABLE(); // implemented as macro in the parser
13294 return NULL;
13295}
13296
13297
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013298#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13299 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013300 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013301 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13302 }
13303
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013304ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013305ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13306ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13307ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13308ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13309ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13310ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13311ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13312ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13313ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13314ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13315ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13316ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13317ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13318
13319#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13320
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013321
13322RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13323 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013324 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
13325 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013326 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13327}
13328
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013329// ----------------------------------------------------------------------------
13330// Implementation of Runtime
13331
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013332#define F(name, number_of_args, result_size) \
13333 { Runtime::k##name, Runtime::RUNTIME, #name, \
13334 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013335
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013336
13337#define I(name, number_of_args, result_size) \
13338 { Runtime::kInline##name, Runtime::INLINE, \
13339 "_" #name, NULL, number_of_args, result_size },
13340
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013341static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013342 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013343 INLINE_FUNCTION_LIST(I)
13344 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013345};
13346
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013347
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013348MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13349 Object* dictionary) {
13350 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013351 ASSERT(dictionary != NULL);
13352 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13353 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013354 Object* name_symbol;
13355 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013356 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013357 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13358 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013359 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013360 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13361 String::cast(name_symbol),
13362 Smi::FromInt(i),
13363 PropertyDetails(NONE, NORMAL));
13364 if (!maybe_dictionary->ToObject(&dictionary)) {
13365 // Non-recoverable failure. Calling code must restart heap
13366 // initialization.
13367 return maybe_dictionary;
13368 }
13369 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013370 }
13371 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013372}
13373
13374
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013375const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13376 Heap* heap = name->GetHeap();
13377 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013378 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013379 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013380 int function_index = Smi::cast(smi_index)->value();
13381 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013382 }
13383 return NULL;
13384}
13385
13386
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013387const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013388 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13389}
13390
13391
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013392void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013393 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013394 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013395 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013396 if (isolate->heap()->new_space()->AddFreshPage()) {
13397 return;
13398 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000013399
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013400 // Try to do a garbage collection; ignore it if it fails. The C
13401 // entry stub will throw an out-of-memory exception in that case.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013402 isolate->heap()->CollectGarbage(failure->allocation_space(),
13403 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013404 } else {
13405 // Handle last resort GC and make sure to allow future allocations
13406 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013407 isolate->counters()->gc_last_resort_from_js()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013408 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13409 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013410 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013411}
13412
13413
13414} } // namespace v8::internal