blob: 15252ed19e15136b97f6b1abb3aa32759e4f7838 [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"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000045#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000047#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000048#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000049#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000050#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000051#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000053#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000056#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000058#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000059#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000060#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062namespace v8 {
63namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65
ager@chromium.org3e875802009-06-29 08:26:34 +000066#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
69// Cast the given object to a value of the specified type and store
70// it in a variable with the given name. If the object is not of the
71// expected type call IllegalOperation and return.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000072#define CONVERT_ARG_CHECKED(Type, name, index) \
73 RUNTIME_ASSERT(args[index]->Is##Type()); \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000074 Type* name = Type::cast(args[index]);
75
76#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \
77 RUNTIME_ASSERT(args[index]->Is##Type()); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000078 Handle<Type> name = args.at<Type>(index);
79
kasper.lundbd3ec4e2008-07-09 11:06:54 +000080// Cast the given object to a boolean and store it in a variable with
81// the given name. If the object is not a boolean call IllegalOperation
82// and return.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000083#define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \
84 RUNTIME_ASSERT(args[index]->IsBoolean()); \
85 bool name = args[index]->IsTrue();
kasper.lundbd3ec4e2008-07-09 11:06:54 +000086
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000087// Cast the given argument to a Smi and store its value in an int variable
88// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000089// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000090#define CONVERT_SMI_ARG_CHECKED(name, index) \
91 RUNTIME_ASSERT(args[index]->IsSmi()); \
92 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000093
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000094// Cast the given argument to a double and store it in a variable with
95// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000097#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
98 RUNTIME_ASSERT(args[index]->IsNumber()); \
99 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101// Call the specified converter on the object *comand store the result in
102// a variable of the specified type with the given name. If the
103// object is not a Number call IllegalOperation and return.
104#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
105 RUNTIME_ASSERT(obj->IsNumber()); \
106 type name = NumberTo##Type(obj);
107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000109// Cast the given argument to PropertyDetails and store its value in a
110// variable with the given name. If the argument is not a Smi call
111// IllegalOperation and return.
112#define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \
113 RUNTIME_ASSERT(args[index]->IsSmi()); \
114 PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
115
116
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000117// Assert that the given argument has a valid value for a StrictModeFlag
118// and store it in a StrictModeFlag variable with the given name.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000119#define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \
120 RUNTIME_ASSERT(args[index]->IsSmi()); \
121 RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \
122 args.smi_at(index) == kNonStrictMode); \
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000123 StrictModeFlag name = \
124 static_cast<StrictModeFlag>(args.smi_at(index));
125
126
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000127// Assert that the given argument has a valid value for a LanguageMode
128// and store it in a LanguageMode variable with the given name.
129#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
130 ASSERT(args[index]->IsSmi()); \
131 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
132 args.smi_at(index) == STRICT_MODE || \
133 args.smi_at(index) == EXTENDED_MODE); \
134 LanguageMode name = \
135 static_cast<LanguageMode>(args.smi_at(index));
136
137
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000138MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
139 JSObject* boilerplate) {
140 StackLimitCheck check(isolate);
141 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000142
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000143 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000144 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000145 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000146 if (!maybe_result->ToObject(&result)) return maybe_result;
147 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000148 JSObject* copy = JSObject::cast(result);
149
150 // Deep copy local properties.
151 if (copy->HasFastProperties()) {
152 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 for (int i = 0; i < properties->length(); i++) {
154 Object* value = properties->get(i);
155 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000156 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000157 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000158 if (!maybe_result->ToObject(&result)) return maybe_result;
159 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000160 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000161 }
162 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000163 int nof = copy->map()->inobject_properties();
164 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000165 Object* value = copy->InObjectPropertyAt(i);
166 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000167 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000168 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000169 if (!maybe_result->ToObject(&result)) return maybe_result;
170 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000171 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000172 }
173 }
174 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000175 { MaybeObject* maybe_result =
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000176 heap->AllocateFixedArray(copy->NumberOfLocalProperties());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000177 if (!maybe_result->ToObject(&result)) return maybe_result;
178 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000179 FixedArray* names = FixedArray::cast(result);
180 copy->GetLocalPropertyNames(names, 0);
181 for (int i = 0; i < names->length(); i++) {
182 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000183 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000184 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000185 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000186 // Only deep copy fields from the object literal expression.
187 // In particular, don't try to copy the length attribute of
188 // an array.
189 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000190 Object* value =
191 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000192 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000193 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000194 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000195 if (!maybe_result->ToObject(&result)) return maybe_result;
196 }
197 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000198 // Creating object copy for literals. No strict mode needed.
199 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000200 if (!maybe_result->ToObject(&result)) return maybe_result;
201 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000202 }
203 }
204 }
205
206 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000207 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000208 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000209 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000210 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000211 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000212 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000213 if (elements->map() == heap->fixed_cow_array_map()) {
214 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000215#ifdef DEBUG
216 for (int i = 0; i < elements->length(); i++) {
217 ASSERT(!elements->get(i)->IsJSObject());
218 }
219#endif
220 } else {
221 for (int i = 0; i < elements->length(); i++) {
222 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000223 ASSERT(value->IsSmi() ||
224 value->IsTheHole() ||
225 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000226 if (value->IsJSObject()) {
227 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000228 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
229 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000230 if (!maybe_result->ToObject(&result)) return maybe_result;
231 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000232 elements->set(i, result);
233 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000234 }
235 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000236 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000237 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000238 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000239 SeededNumberDictionary* element_dictionary = copy->element_dictionary();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000240 int capacity = element_dictionary->Capacity();
241 for (int i = 0; i < capacity; i++) {
242 Object* k = element_dictionary->KeyAt(i);
243 if (element_dictionary->IsKey(k)) {
244 Object* value = element_dictionary->ValueAt(i);
245 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000246 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000247 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
248 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000249 if (!maybe_result->ToObject(&result)) return maybe_result;
250 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000251 element_dictionary->ValueAtPut(i, result);
252 }
253 }
254 }
255 break;
256 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000257 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000258 UNIMPLEMENTED();
259 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000260 case EXTERNAL_PIXEL_ELEMENTS:
261 case EXTERNAL_BYTE_ELEMENTS:
262 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
263 case EXTERNAL_SHORT_ELEMENTS:
264 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
265 case EXTERNAL_INT_ELEMENTS:
266 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
267 case EXTERNAL_FLOAT_ELEMENTS:
268 case EXTERNAL_DOUBLE_ELEMENTS:
269 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000270 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000271 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000272 }
273 return copy;
274}
275
276
ager@chromium.org236ad962008-09-25 09:45:57 +0000277static Handle<Map> ComputeObjectLiteralMap(
278 Handle<Context> context,
279 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000280 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000281 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000282 int properties_length = constant_properties->length();
283 int number_of_properties = properties_length / 2;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000284 // Check that there are only symbols and array indices among keys.
285 int number_of_symbol_keys = 0;
286 for (int p = 0; p != properties_length; p += 2) {
287 Object* key = constant_properties->get(p);
288 uint32_t element_index = 0;
289 if (key->IsSymbol()) {
290 number_of_symbol_keys++;
291 } else if (key->ToArrayIndex(&element_index)) {
292 // An index key does not require space in the property backing store.
293 number_of_properties--;
294 } else {
295 // Bail out as a non-symbol non-index key makes caching impossible.
296 // ASSERT to make sure that the if condition after the loop is false.
297 ASSERT(number_of_symbol_keys != number_of_properties);
298 break;
ager@chromium.org236ad962008-09-25 09:45:57 +0000299 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000300 }
301 // If we only have symbols and array indices among keys then we can
302 // use the map cache in the global context.
303 const int kMaxKeys = 10;
304 if ((number_of_symbol_keys == number_of_properties) &&
305 (number_of_symbol_keys < kMaxKeys)) {
306 // Create the fixed array with the key.
307 Handle<FixedArray> keys =
308 isolate->factory()->NewFixedArray(number_of_symbol_keys);
309 if (number_of_symbol_keys > 0) {
310 int index = 0;
311 for (int p = 0; p < properties_length; p += 2) {
312 Object* key = constant_properties->get(p);
313 if (key->IsSymbol()) {
314 keys->set(index++, key);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000315 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000316 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000317 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000318 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000319 *is_result_from_cache = true;
320 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000321 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000322 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000323 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000324 Handle<Map>(context->object_function()->initial_map()),
325 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000326}
327
328
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000329static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000331 Handle<FixedArray> literals,
332 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000333
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000334
335static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000336 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000337 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000338 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000339 bool should_have_fast_elements,
340 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000341 // Get the global context from the literals array. This is the
342 // context in which the function was created and we use the object
343 // function from this context to create the object literal. We do
344 // not use the object function from the current global context
345 // because this might be the object function from another context
346 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000347 Handle<Context> context =
348 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
349
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000350 // In case we have function literals, we want the object to be in
351 // slow properties mode for now. We don't go in the map cache because
352 // maps with constant functions can't be shared if the functions are
353 // not the same (which is the common case).
354 bool is_result_from_cache = false;
355 Handle<Map> map = has_function_literal
356 ? Handle<Map>(context->object_function()->initial_map())
357 : ComputeObjectLiteralMap(context,
358 constant_properties,
359 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000361 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000362
363 // Normalize the elements of the boilerplate to save space if needed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000364 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000365
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000366 // Add the constant properties to the boilerplate.
367 int length = constant_properties->length();
368 bool should_transform =
369 !is_result_from_cache && boilerplate->HasFastProperties();
370 if (should_transform || has_function_literal) {
371 // Normalize the properties of object to avoid n^2 behavior
372 // when extending the object multiple properties. Indicate the number of
373 // properties to be added.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000374 JSObject::NormalizeProperties(
375 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000376 }
377
378 for (int index = 0; index < length; index +=2) {
379 Handle<Object> key(constant_properties->get(index+0), isolate);
380 Handle<Object> value(constant_properties->get(index+1), isolate);
381 if (value->IsFixedArray()) {
382 // The value contains the constant_properties of a
383 // simple object or array literal.
384 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
385 value = CreateLiteralBoilerplate(isolate, literals, array);
386 if (value.is_null()) return value;
387 }
388 Handle<Object> result;
389 uint32_t element_index = 0;
390 if (key->IsSymbol()) {
391 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
392 // Array index as string (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000393 result = JSObject::SetOwnElement(
394 boilerplate, element_index, value, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000395 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000396 Handle<String> name(String::cast(*key));
397 ASSERT(!name->AsArrayIndex(&element_index));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000398 result = JSObject::SetLocalPropertyIgnoreAttributes(
399 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000401 } else if (key->ToArrayIndex(&element_index)) {
402 // Array index (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000403 result = JSObject::SetOwnElement(
404 boilerplate, element_index, value, kNonStrictMode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000405 } else {
406 // Non-uint32 number.
407 ASSERT(key->IsNumber());
408 double num = key->Number();
409 char arr[100];
410 Vector<char> buffer(arr, ARRAY_SIZE(arr));
411 const char* str = DoubleToCString(num, buffer);
412 Handle<String> name =
413 isolate->factory()->NewStringFromAscii(CStrVector(str));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000414 result = JSObject::SetLocalPropertyIgnoreAttributes(
415 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000416 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000417 // If setting the property on the boilerplate throws an
418 // exception, the exception is converted to an empty handle in
419 // the handle based operations. In that case, we need to
420 // convert back to an exception.
421 if (result.is_null()) return result;
422 }
423
424 // Transform to fast properties if necessary. For object literals with
425 // containing function literals we defer this operation until after all
426 // computed properties have been assigned so that we can generate
427 // constant function properties.
428 if (should_transform && !has_function_literal) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000429 JSObject::TransformToFastProperties(
430 boilerplate, boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000431 }
432
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000433 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000434}
435
436
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000437MaybeObject* TransitionElements(Handle<Object> object,
438 ElementsKind to_kind,
439 Isolate* isolate) {
440 HandleScope scope(isolate);
441 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
442 ElementsKind from_kind =
443 Handle<JSObject>::cast(object)->map()->elements_kind();
444 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
445 Handle<Object> result = JSObject::TransitionElementsKind(
446 Handle<JSObject>::cast(object), to_kind);
447 if (result.is_null()) return isolate->ThrowIllegalOperation();
448 return *result;
449 }
450 return isolate->ThrowIllegalOperation();
451}
452
453
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000454static const int kSmiOnlyLiteralMinimumLength = 1024;
455
456
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000457Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000458 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000459 Handle<FixedArray> literals,
460 Handle<FixedArray> elements) {
461 // Create the JSArray.
462 Handle<JSFunction> constructor(
463 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000464 Handle<JSArray> object =
465 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000466
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000467 ElementsKind constant_elements_kind =
468 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
469 Handle<FixedArrayBase> constant_elements_values(
470 FixedArrayBase::cast(elements->get(1)));
471
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000472 Context* global_context = isolate->context()->global_context();
473 if (constant_elements_kind == FAST_SMI_ONLY_ELEMENTS) {
474 object->set_map(Map::cast(global_context->smi_js_array_map()));
475 } else if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
476 object->set_map(Map::cast(global_context->double_js_array_map()));
477 } else {
478 object->set_map(Map::cast(global_context->object_js_array_map()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000479 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000480
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000481 Handle<FixedArrayBase> copied_elements_values;
482 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
483 ASSERT(FLAG_smi_only_arrays);
484 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
485 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000486 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000487 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
488 constant_elements_kind == FAST_ELEMENTS);
489 const bool is_cow =
490 (constant_elements_values->map() ==
491 isolate->heap()->fixed_cow_array_map());
492 if (is_cow) {
493 copied_elements_values = constant_elements_values;
494#if DEBUG
495 Handle<FixedArray> fixed_array_values =
496 Handle<FixedArray>::cast(copied_elements_values);
497 for (int i = 0; i < fixed_array_values->length(); i++) {
498 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
499 }
500#endif
501 } else {
502 Handle<FixedArray> fixed_array_values =
503 Handle<FixedArray>::cast(constant_elements_values);
504 Handle<FixedArray> fixed_array_values_copy =
505 isolate->factory()->CopyFixedArray(fixed_array_values);
506 copied_elements_values = fixed_array_values_copy;
507 for (int i = 0; i < fixed_array_values->length(); i++) {
508 Object* current = fixed_array_values->get(i);
509 if (current->IsFixedArray()) {
510 // The value contains the constant_properties of a
511 // simple object or array literal.
512 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
513 Handle<Object> result =
514 CreateLiteralBoilerplate(isolate, literals, fa);
515 if (result.is_null()) return result;
516 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000517 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000518 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000519 }
520 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000521 object->set_elements(*copied_elements_values);
522 object->set_length(Smi::FromInt(copied_elements_values->length()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000523
524 // Ensure that the boilerplate object has FAST_ELEMENTS, unless the flag is
525 // on or the object is larger than the threshold.
526 if (!FLAG_smi_only_arrays &&
527 constant_elements_values->length() < kSmiOnlyLiteralMinimumLength) {
528 if (object->GetElementsKind() != FAST_ELEMENTS) {
529 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
530 }
531 }
532
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000533 return object;
534}
535
536
537static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000538 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000539 Handle<FixedArray> literals,
540 Handle<FixedArray> array) {
541 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000542 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000543 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000544 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 return CreateObjectLiteralBoilerplate(isolate,
546 literals,
547 elements,
548 true,
549 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000550 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000551 return CreateObjectLiteralBoilerplate(isolate,
552 literals,
553 elements,
554 false,
555 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000556 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000557 return Runtime::CreateArrayLiteralBoilerplate(
558 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000559 default:
560 UNREACHABLE();
561 return Handle<Object>::null();
562 }
563}
564
565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000566RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000567 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000568 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000569 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000570 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000571 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000572 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000573 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
574 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000575
576 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577 Handle<Object> boilerplate(literals->get(literals_index), isolate);
578 if (*boilerplate == isolate->heap()->undefined_value()) {
579 boilerplate = CreateObjectLiteralBoilerplate(isolate,
580 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000581 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000582 should_have_fast_elements,
583 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000584 if (boilerplate.is_null()) return Failure::Exception();
585 // Update the functions literal and return the boilerplate.
586 literals->set(literals_index, *boilerplate);
587 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000588 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000589}
590
591
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000592RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000593 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000594 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000595 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000596 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000597 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000598 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
600 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000601
602 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000603 Handle<Object> boilerplate(literals->get(literals_index), isolate);
604 if (*boilerplate == isolate->heap()->undefined_value()) {
605 boilerplate = CreateObjectLiteralBoilerplate(isolate,
606 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000607 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000608 should_have_fast_elements,
609 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000610 if (boilerplate.is_null()) return Failure::Exception();
611 // Update the functions literal and return the boilerplate.
612 literals->set(literals_index, *boilerplate);
613 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000614 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000615}
616
617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000618RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000619 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000620 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000621 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000622 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000623 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000624
625 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000626 Handle<Object> boilerplate(literals->get(literals_index), isolate);
627 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000628 boilerplate =
629 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000630 if (boilerplate.is_null()) return Failure::Exception();
631 // Update the functions literal and return the boilerplate.
632 literals->set(literals_index, *boilerplate);
633 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000634 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000635}
636
637
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000638RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000639 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000640 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000641 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000642 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000643 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000644
645 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000646 Handle<Object> boilerplate(literals->get(literals_index), isolate);
647 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000648 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000649 boilerplate =
650 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000651 if (boilerplate.is_null()) return Failure::Exception();
652 // Update the functions literal and return the boilerplate.
653 literals->set(literals_index, *boilerplate);
654 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000655 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000656 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000657 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000658 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000659 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000660}
661
662
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000663RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
664 ASSERT(args.length() == 2);
665 Object* handler = args[0];
666 Object* prototype = args[1];
667 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000668 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000669 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
670}
671
672
lrn@chromium.org34e60782011-09-15 07:25:40 +0000673RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
674 ASSERT(args.length() == 4);
675 Object* handler = args[0];
676 Object* call_trap = args[1];
677 Object* construct_trap = args[2];
678 Object* prototype = args[3];
679 Object* used_prototype =
680 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
681 return isolate->heap()->AllocateJSFunctionProxy(
682 handler, call_trap, construct_trap, used_prototype);
683}
684
685
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000686RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
687 ASSERT(args.length() == 1);
688 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000689 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000690}
691
692
lrn@chromium.org34e60782011-09-15 07:25:40 +0000693RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
694 ASSERT(args.length() == 1);
695 Object* obj = args[0];
696 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
697}
698
699
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000700RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
701 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000702 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000703 return proxy->handler();
704}
705
706
lrn@chromium.org34e60782011-09-15 07:25:40 +0000707RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
708 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000709 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000710 return proxy->call_trap();
711}
712
713
714RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
715 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000716 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000717 return proxy->construct_trap();
718}
719
720
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000721RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
722 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000723 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000724 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000725 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000726}
727
728
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000729RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
730 HandleScope scope(isolate);
731 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000732 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000733 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
734 holder->set_table(*table);
735 return *holder;
736}
737
738
739RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
740 HandleScope scope(isolate);
741 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000742 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000743 Handle<Object> key(args[1]);
744 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
745 table = ObjectHashSetAdd(table, key);
746 holder->set_table(*table);
747 return isolate->heap()->undefined_symbol();
748}
749
750
751RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
752 HandleScope scope(isolate);
753 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000754 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000755 Handle<Object> key(args[1]);
756 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
757 return isolate->heap()->ToBoolean(table->Contains(*key));
758}
759
760
761RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
762 HandleScope scope(isolate);
763 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000764 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000765 Handle<Object> key(args[1]);
766 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
767 table = ObjectHashSetRemove(table, key);
768 holder->set_table(*table);
769 return isolate->heap()->undefined_symbol();
770}
771
772
773RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
774 HandleScope scope(isolate);
775 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000776 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000777 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
778 holder->set_table(*table);
779 return *holder;
780}
781
782
783RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
784 HandleScope scope(isolate);
785 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000786 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000787 Handle<Object> key(args[1]);
788 return ObjectHashTable::cast(holder->table())->Lookup(*key);
789}
790
791
792RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
793 HandleScope scope(isolate);
794 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000795 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000796 Handle<Object> key(args[1]);
797 Handle<Object> value(args[2]);
798 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
799 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
800 holder->set_table(*new_table);
801 return *value;
802}
803
804
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000805RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
806 HandleScope scope(isolate);
807 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000808 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000809 ASSERT(weakmap->map()->inobject_properties() == 0);
810 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
811 weakmap->set_table(*table);
812 weakmap->set_next(Smi::FromInt(0));
813 return *weakmap;
814}
815
816
817RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
818 NoHandleAllocation ha;
819 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000820 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
821 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000822 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000823}
824
825
826RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
827 HandleScope scope(isolate);
828 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000829 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
830 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000831 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000832 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000833 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
834 weakmap->set_table(*new_table);
835 return *value;
836}
837
838
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000839RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000840 NoHandleAllocation ha;
841 ASSERT(args.length() == 1);
842 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000843 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000844 return JSObject::cast(obj)->class_name();
845}
846
ager@chromium.org7c537e22008-10-16 08:43:32 +0000847
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000848RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
849 NoHandleAllocation ha;
850 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000851 CONVERT_ARG_CHECKED(JSReceiver, input_obj, 0);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000852 Object* obj = input_obj;
853 // We don't expect access checks to be needed on JSProxy objects.
854 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000855 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000856 if (obj->IsAccessCheckNeeded() &&
857 !isolate->MayNamedAccess(JSObject::cast(obj),
858 isolate->heap()->Proto_symbol(),
859 v8::ACCESS_GET)) {
860 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
861 return isolate->heap()->undefined_value();
862 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000863 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000864 } while (obj->IsJSObject() &&
865 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000866 return obj;
867}
868
869
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000870RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000871 NoHandleAllocation ha;
872 ASSERT(args.length() == 2);
873 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
874 Object* O = args[0];
875 Object* V = args[1];
876 while (true) {
877 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000878 if (prototype->IsNull()) return isolate->heap()->false_value();
879 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000880 V = prototype;
881 }
882}
883
884
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000885RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000886 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000887 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000888 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000889 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000890}
891
892
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000893// Recursively traverses hidden prototypes if property is not found
894static void GetOwnPropertyImplementation(JSObject* obj,
895 String* name,
896 LookupResult* result) {
897 obj->LocalLookupRealNamedProperty(name, result);
898
899 if (!result->IsProperty()) {
900 Object* proto = obj->GetPrototype();
901 if (proto->IsJSObject() &&
902 JSObject::cast(proto)->map()->is_hidden_prototype())
903 GetOwnPropertyImplementation(JSObject::cast(proto),
904 name, result);
905 }
906}
907
908
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000909static bool CheckAccessException(LookupResult* result,
910 v8::AccessType access_type) {
911 if (result->type() == CALLBACKS) {
912 Object* callback = result->GetCallbackObject();
913 if (callback->IsAccessorInfo()) {
914 AccessorInfo* info = AccessorInfo::cast(callback);
915 bool can_access =
916 (access_type == v8::ACCESS_HAS &&
917 (info->all_can_read() || info->all_can_write())) ||
918 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
919 (access_type == v8::ACCESS_SET && info->all_can_write());
920 return can_access;
921 }
922 }
923
924 return false;
925}
926
927
928static bool CheckAccess(JSObject* obj,
929 String* name,
930 LookupResult* result,
931 v8::AccessType access_type) {
932 ASSERT(result->IsProperty());
933
934 JSObject* holder = result->holder();
935 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000936 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000937 while (true) {
938 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000939 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000940 // Access check callback denied the access, but some properties
941 // can have a special permissions which override callbacks descision
942 // (currently see v8::AccessControl).
943 break;
944 }
945
946 if (current == holder) {
947 return true;
948 }
949
950 current = JSObject::cast(current->GetPrototype());
951 }
952
953 // API callbacks can have per callback access exceptions.
954 switch (result->type()) {
955 case CALLBACKS: {
956 if (CheckAccessException(result, access_type)) {
957 return true;
958 }
959 break;
960 }
961 case INTERCEPTOR: {
962 // If the object has an interceptor, try real named properties.
963 // Overwrite the result to fetch the correct property later.
964 holder->LookupRealNamedProperty(name, result);
965 if (result->IsProperty()) {
966 if (CheckAccessException(result, access_type)) {
967 return true;
968 }
969 }
970 break;
971 }
972 default:
973 break;
974 }
975
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000976 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000977 return false;
978}
979
980
981// TODO(1095): we should traverse hidden prototype hierachy as well.
982static bool CheckElementAccess(JSObject* obj,
983 uint32_t index,
984 v8::AccessType access_type) {
985 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000986 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000987 return false;
988 }
989
990 return true;
991}
992
993
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000994// Enumerator used as indices into the array returned from GetOwnProperty
995enum PropertyDescriptorIndices {
996 IS_ACCESSOR_INDEX,
997 VALUE_INDEX,
998 GETTER_INDEX,
999 SETTER_INDEX,
1000 WRITABLE_INDEX,
1001 ENUMERABLE_INDEX,
1002 CONFIGURABLE_INDEX,
1003 DESCRIPTOR_SIZE
1004};
1005
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001006// Returns an array with the property description:
1007// if args[1] is not a property on args[0]
1008// returns undefined
1009// if args[1] is a data property on args[0]
1010// [false, value, Writeable, Enumerable, Configurable]
1011// if args[1] is an accessor on args[0]
1012// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001013RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001014 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001015 Heap* heap = isolate->heap();
1016 HandleScope scope(isolate);
1017 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1018 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001019 LookupResult result(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001020 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1021 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001022
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001023 // This could be an element.
1024 uint32_t index;
1025 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001026 switch (obj->HasLocalElement(index)) {
1027 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001028 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001029
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001030 case JSObject::STRING_CHARACTER_ELEMENT: {
1031 // Special handling of string objects according to ECMAScript 5
1032 // 15.5.5.2. Note that this might be a string object with elements
1033 // other than the actual string value. This is covered by the
1034 // subsequent cases.
1035 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1036 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001037 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001038
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001039 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001040 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001041 elms->set(WRITABLE_INDEX, heap->false_value());
1042 elms->set(ENUMERABLE_INDEX, heap->false_value());
1043 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001044 return *desc;
1045 }
1046
1047 case JSObject::INTERCEPTED_ELEMENT:
1048 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001049 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001050 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001051 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001052 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001053 elms->set(WRITABLE_INDEX, heap->true_value());
1054 elms->set(ENUMERABLE_INDEX, heap->true_value());
1055 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001056 return *desc;
1057 }
1058
1059 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001060 Handle<JSObject> holder = obj;
1061 if (obj->IsJSGlobalProxy()) {
1062 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001063 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001064 ASSERT(proto->IsJSGlobalObject());
1065 holder = Handle<JSObject>(JSObject::cast(proto));
1066 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001067 FixedArray* elements = FixedArray::cast(holder->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001068 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001069 if (elements->map() == heap->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001070 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001071 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001072 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001073 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001074 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001075 ASSERT(entry != SeededNumberDictionary::kNotFound);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001076 PropertyDetails details = dictionary->DetailsAt(entry);
1077 switch (details.type()) {
1078 case CALLBACKS: {
1079 // This is an accessor property with getter and/or setter.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001080 AccessorPair* accessors =
1081 AccessorPair::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001082 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001083 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001084 elms->set(GETTER_INDEX, accessors->getter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001085 }
1086 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001087 elms->set(SETTER_INDEX, accessors->setter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001088 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001089 break;
1090 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001091 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001092 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001093 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001094 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001095 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001096 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001097 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001098 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001099 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001100 default:
1101 UNREACHABLE();
1102 break;
1103 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001104 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1105 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001106 return *desc;
1107 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001108 }
1109 }
1110
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001111 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001112 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001113
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001114 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001115 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001116 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001117
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001118 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001119 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001120 }
1121
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001122 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1123 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001124
1125 bool is_js_accessor = (result.type() == CALLBACKS) &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001126 (result.GetCallbackObject()->IsAccessorPair());
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001127
1128 if (is_js_accessor) {
1129 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001130 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001131
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001132 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001133 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001134 elms->set(GETTER_INDEX, accessors->getter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001135 }
1136 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001137 elms->set(SETTER_INDEX, accessors->setter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001138 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001139 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001140 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1141 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001142
1143 PropertyAttributes attrs;
1144 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001145 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001146 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1147 if (!maybe_value->ToObject(&value)) return maybe_value;
1148 }
1149 elms->set(VALUE_INDEX, value);
1150 }
1151
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001152 return *desc;
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.
1292 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001293 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294 if (value->IsUndefined() || is_const_property) {
1295 // Lookup the property in the global object, and don't set the
1296 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001297 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298 global->Lookup(*name, &lookup);
1299 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001300 // We found an existing property. Unless it was an interceptor
1301 // that claims the property is absent, skip this declaration.
1302 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303 continue;
1304 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001305 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1306 if (attributes != ABSENT) {
1307 continue;
1308 }
1309 // Fall-through and introduce the absent property by using
1310 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311 }
1312 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001313 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001314 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001315 Handle<SharedFunctionInfo> shared =
1316 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001317 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001318 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1319 context,
1320 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001321 value = function;
1322 }
1323
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001324 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325 global->LocalLookup(*name, &lookup);
1326
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001327 // Compute the property attributes. According to ECMA-262, section
1328 // 13, page 71, the property must be read-only and
1329 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1330 // property as read-only, so we don't either.
1331 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001332 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001333 attr |= DONT_DELETE;
1334 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001335 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001336 if (is_const_property || (is_native && is_function_declaration)) {
1337 attr |= READ_ONLY;
1338 }
1339
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001340 // Safari does not allow the invocation of callback setters for
1341 // function declarations. To mimic this behavior, we do not allow
1342 // the invocation of setters for function values. This makes a
1343 // difference for global functions with the same names as event
1344 // handlers such as "function onload() {}". Firefox does call the
1345 // onload setter in those case and Safari does not. We follow
1346 // Safari for compatibility.
1347 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001348 // Do not change DONT_DELETE to false from true.
1349 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001350 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001351 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001352 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1353
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001354 RETURN_IF_EMPTY_HANDLE(
1355 isolate,
1356 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
1357 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358 } else {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001359 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1360 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1361 ? kNonStrictMode : kStrictMode;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001362 RETURN_IF_EMPTY_HANDLE(
1363 isolate,
1364 JSReceiver::SetProperty(global, name, value,
1365 static_cast<PropertyAttributes>(attr),
1366 strict_mode_flag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001367 }
1368 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001369
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001370 ASSERT(!isolate->has_pending_exception());
1371 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001372}
1373
1374
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001375RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001376 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001377 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001378
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001379 // Declarations are always made in a function or global context. In the
1380 // case of eval code, the context passed is the context of the caller,
1381 // which may be some nested context and not the declaration context.
1382 RUNTIME_ASSERT(args[0]->IsContext());
1383 Handle<Context> context(Context::cast(args[0])->declaration_context());
1384
ager@chromium.org7c537e22008-10-16 08:43:32 +00001385 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001386 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001387 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001388 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001389
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001390 int index;
1391 PropertyAttributes attributes;
1392 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001393 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001394 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001395 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001396
1397 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001398 // The name was declared before; check for conflicting re-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.comf2038fb2012-01-16 11:42:08 +00001461 RETURN_IF_EMPTY_HANDLE(
1462 isolate,
1463 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001464 }
1465
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001466 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001467}
1468
1469
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001470RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001471 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001472 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001473 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001474 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001475
1476 // Determine if we need to assign to the variable if it already
1477 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001478 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1479 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001480
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001481 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001482 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001483 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001484 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1485 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1486 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001487
1488 // According to ECMA-262, section 12.2, page 62, the property must
1489 // not be deletable.
1490 PropertyAttributes attributes = DONT_DELETE;
1491
1492 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001493 // there, there is a property with this name in the prototype chain.
1494 // We follow Safari and Firefox behavior and only set the property
1495 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001496 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001497 // Note that objects can have hidden prototypes, so we need to traverse
1498 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001499 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001500 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001501 while (object->IsJSObject() &&
1502 JSObject::cast(object)->map()->is_hidden_prototype()) {
1503 JSObject* raw_holder = JSObject::cast(object);
1504 raw_holder->LocalLookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001505 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001506 HandleScope handle_scope(isolate);
1507 Handle<JSObject> holder(raw_holder);
1508 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1509 // Update the raw pointer in case it's changed due to GC.
1510 raw_holder = *holder;
1511 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1512 // Found an interceptor that's not read only.
1513 if (assign) {
1514 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001515 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001516 } else {
1517 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001518 }
1519 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001520 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001521 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001522 }
1523
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001524 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001525 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001526 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001527 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001528 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001529 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001530}
1531
1532
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001533RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534 // All constants are declared with an initial value. The name
1535 // of the constant is the first argument and the initial value
1536 // is the second.
1537 RUNTIME_ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001538 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001539 Handle<Object> value = args.at<Object>(1);
1540
1541 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001542 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543
1544 // According to ECMA-262, section 12.2, page 62, the property must
1545 // not be deletable. Since it's a const, it must be READ_ONLY too.
1546 PropertyAttributes attributes =
1547 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1548
1549 // Lookup the property locally in the global object. If it isn't
1550 // there, we add the property and take special precautions to always
1551 // add it as a local property even in case of callbacks in the
1552 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001553 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001554 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555 global->LocalLookup(*name, &lookup);
1556 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001557 return global->SetLocalPropertyIgnoreAttributes(*name,
1558 *value,
1559 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 }
1561
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001562 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001563 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001564 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001565 HandleScope handle_scope(isolate);
1566 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001567
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001568 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001569 // property through an interceptor and only do it if it's
1570 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001571 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001572 RETURN_IF_EMPTY_HANDLE(
1573 isolate,
1574 JSReceiver::SetProperty(global, name, value, attributes,
1575 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001576 return *value;
1577 }
1578
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001579 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001580 // constant. For now, we determine this by checking if the
1581 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001582 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001583 PropertyType type = lookup.type();
1584 if (type == FIELD) {
1585 FixedArray* properties = global->properties();
1586 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001587 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001588 properties->set(index, *value);
1589 }
1590 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001591 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1592 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001593 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001594 }
1595 } else {
1596 // Ignore re-initialization of constants that have already been
1597 // assigned a function value.
1598 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1599 }
1600
1601 // Use the set value as the result of the operation.
1602 return *value;
1603}
1604
1605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001606RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001607 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001608 ASSERT(args.length() == 3);
1609
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001610 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001611 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001612
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001613 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001614 RUNTIME_ASSERT(args[1]->IsContext());
1615 Handle<Context> context(Context::cast(args[1])->declaration_context());
1616
1617 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001618
1619 int index;
1620 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001621 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001622 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001623 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001624 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001625
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001626 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001627 ASSERT(holder->IsContext());
1628 // Property was found in a context. Perform the assignment if we
1629 // found some non-constant or an uninitialized constant.
1630 Handle<Context> context = Handle<Context>::cast(holder);
1631 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1632 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001633 }
1634 return *value;
1635 }
1636
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001637 // The property could not be found, we introduce it as a property of the
1638 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001639 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001640 Handle<JSObject> global = Handle<JSObject>(
1641 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001642 // Strict mode not needed (const disallowed in strict mode).
1643 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001644 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001645 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001646 return *value;
1647 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001648
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001649 // The property was present in some function's context extension object,
1650 // as a property on the subject of a with, or as a property of the global
1651 // object.
1652 //
1653 // In most situations, eval-introduced consts should still be present in
1654 // the context extension object. However, because declaration and
1655 // initialization are separate, the property might have been deleted
1656 // before we reach the initialization point.
1657 //
1658 // Example:
1659 //
1660 // function f() { eval("delete x; const x;"); }
1661 //
1662 // In that case, the initialization behaves like a normal assignment.
1663 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001664
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001665 if (*object == context->extension()) {
1666 // This is the property that was introduced by the const declaration.
1667 // Set it if it hasn't been set before. NOTE: We cannot use
1668 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001669 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001670 object->LocalLookupRealNamedProperty(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001671 ASSERT(lookup.IsFound()); // the property was declared
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001672 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1673
1674 PropertyType type = lookup.type();
1675 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001676 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001677 int index = lookup.GetFieldIndex();
1678 if (properties->get(index)->IsTheHole()) {
1679 properties->set(index, *value);
1680 }
1681 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001682 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1683 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001684 }
1685 } else {
1686 // We should not reach here. Any real, named property should be
1687 // either a field or a dictionary slot.
1688 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001689 }
1690 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001691 // The property was found on some other object. Set it if it is not a
1692 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001693 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001694 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001695 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001696 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001697 JSReceiver::SetProperty(object, name, value, attributes,
1698 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001699 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001700 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001701
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001702 return *value;
1703}
1704
1705
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001706RUNTIME_FUNCTION(MaybeObject*,
1707 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001708 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001709 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001710 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001711 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001712 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001713 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001714 }
1715 return *object;
1716}
1717
1718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001719RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001720 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001721 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001722 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
1723 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001724 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001725 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001726 CONVERT_SMI_ARG_CHECKED(index, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001727 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001728 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001729 RUNTIME_ASSERT(index >= 0);
1730 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001732 Handle<Object> result = RegExpImpl::Exec(regexp,
1733 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001734 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001735 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001736 if (result.is_null()) return Failure::Exception();
1737 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001738}
1739
1740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001741RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001742 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001743 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001744 if (elements_count < 0 ||
1745 elements_count > FixedArray::kMaxLength ||
1746 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001747 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001748 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001749 Object* new_object;
1750 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001752 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1753 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001754 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001755 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1756 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
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 {
1760 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001761 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001762 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001764 }
1765 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001766 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001767 array->set_elements(elements);
1768 array->set_length(Smi::FromInt(elements_count));
1769 // Write in-object properties after the length of the array.
1770 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1771 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1772 return array;
1773}
1774
1775
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001776RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001777 AssertNoAllocation no_alloc;
1778 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001779 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1780 CONVERT_ARG_CHECKED(String, source, 1);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001781
1782 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001783 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001784
1785 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001786 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001787
1788 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001789 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001790
1791 Map* map = regexp->map();
1792 Object* constructor = map->constructor();
1793 if (constructor->IsJSFunction() &&
1794 JSFunction::cast(constructor)->initial_map() == map) {
1795 // If we still have the original map, set in-object properties directly.
1796 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001797 // Both true and false are immovable immortal objects so no need for write
1798 // barrier.
1799 regexp->InObjectPropertyAtPut(
1800 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1801 regexp->InObjectPropertyAtPut(
1802 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1803 regexp->InObjectPropertyAtPut(
1804 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001805 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1806 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001807 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001808 return regexp;
1809 }
1810
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001811 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001812 PropertyAttributes final =
1813 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1814 PropertyAttributes writable =
1815 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001816 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001817 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001818 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001819 source,
1820 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001821 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001822 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001823 global,
1824 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001825 ASSERT(!result->IsFailure());
1826 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001827 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001828 ignoreCase,
1829 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001830 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001831 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001832 multiline,
1833 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001834 ASSERT(!result->IsFailure());
1835 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001836 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001837 Smi::FromInt(0),
1838 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001839 ASSERT(!result->IsFailure());
1840 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001841 return regexp;
1842}
1843
1844
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001845RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001846 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001847 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001848 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001849 // This is necessary to enable fast checks for absence of elements
1850 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001851 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001852 return Smi::FromInt(0);
1853}
1854
1855
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001856static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1857 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001858 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001859 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001860 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1861 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1862 Handle<JSFunction> optimized =
1863 isolate->factory()->NewFunction(key,
1864 JS_OBJECT_TYPE,
1865 JSObject::kHeaderSize,
1866 code,
1867 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001868 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001869 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001870 return optimized;
1871}
1872
1873
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001874RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001875 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001876 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001877 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001878
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001879 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1880 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1881 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1882 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1883 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1884 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1885 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001886
1887 return *holder;
1888}
1889
1890
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001891RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001892 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001893 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001894
1895 if (!callable->IsJSFunction()) {
1896 HandleScope scope(isolate);
1897 bool threw = false;
1898 Handle<Object> delegate =
1899 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
1900 if (threw) return Failure::Exception();
1901 callable = JSFunction::cast(*delegate);
1902 }
1903 JSFunction* function = JSFunction::cast(callable);
1904
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001905 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001906 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001907 return isolate->heap()->undefined_value();
1908 }
1909 // Returns undefined for strict or native functions, or
1910 // the associated global receiver for "normal" functions.
1911
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001912 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001913 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001914 return global_context->global()->global_receiver();
1915}
1916
1917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001918RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001919 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001920 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001921 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001922 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001923 Handle<String> pattern = args.at<String>(2);
1924 Handle<String> flags = args.at<String>(3);
1925
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001926 // Get the RegExp function from the context in the literals array.
1927 // This is the RegExp function from the context in which the
1928 // function was created. We do not use the RegExp function from the
1929 // current global context because this might be the RegExp function
1930 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001931 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001932 Handle<JSFunction>(
1933 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001934 // Compute the regular expression literal.
1935 bool has_pending_exception;
1936 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001937 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1938 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001939 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001940 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001941 return Failure::Exception();
1942 }
1943 literals->set(index, *regexp);
1944 return *regexp;
1945}
1946
1947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001948RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001949 NoHandleAllocation ha;
1950 ASSERT(args.length() == 1);
1951
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001952 CONVERT_ARG_CHECKED(JSFunction, f, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001953 return f->shared()->name();
1954}
1955
1956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001957RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001958 NoHandleAllocation ha;
1959 ASSERT(args.length() == 2);
1960
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001961 CONVERT_ARG_CHECKED(JSFunction, f, 0);
1962 CONVERT_ARG_CHECKED(String, name, 1);
ager@chromium.org236ad962008-09-25 09:45:57 +00001963 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001964 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001965}
1966
1967
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001968RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1969 NoHandleAllocation ha;
1970 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001971 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001972 return isolate->heap()->ToBoolean(
1973 f->shared()->name_should_print_as_anonymous());
1974}
1975
1976
1977RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1978 NoHandleAllocation ha;
1979 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001980 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001981 f->shared()->set_name_should_print_as_anonymous(true);
1982 return isolate->heap()->undefined_value();
1983}
1984
1985
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001986RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001987 NoHandleAllocation ha;
1988 ASSERT(args.length() == 1);
1989
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001990 CONVERT_ARG_CHECKED(JSFunction, f, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001991 Object* obj = f->RemovePrototype();
1992 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001993
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001994 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001995}
1996
1997
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001998RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001999 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002000 ASSERT(args.length() == 1);
2001
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002002 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002003 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2004 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002005
2006 return *GetScriptWrapper(Handle<Script>::cast(script));
2007}
2008
2009
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002010RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002011 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002012 ASSERT(args.length() == 1);
2013
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002014 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002015 Handle<SharedFunctionInfo> shared(f->shared());
2016 return *shared->GetSourceCode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002017}
2018
2019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002020RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002021 NoHandleAllocation ha;
2022 ASSERT(args.length() == 1);
2023
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002024 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002025 int pos = fun->shared()->start_position();
2026 return Smi::FromInt(pos);
2027}
2028
2029
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002030RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002031 ASSERT(args.length() == 2);
2032
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002033 CONVERT_ARG_CHECKED(Code, code, 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002034 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2035
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002036 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2037
2038 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002039 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002040}
2041
2042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002043RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002044 NoHandleAllocation ha;
2045 ASSERT(args.length() == 2);
2046
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002047 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2048 CONVERT_ARG_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002049 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002050 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002051}
2052
2053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002054RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002055 NoHandleAllocation ha;
2056 ASSERT(args.length() == 2);
2057
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002058 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2059 CONVERT_SMI_ARG_CHECKED(length, 1);
2060 fun->shared()->set_length(length);
2061 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002062}
2063
2064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002065RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002066 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002067 ASSERT(args.length() == 2);
2068
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002069 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002070 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002071 Object* obj;
2072 { MaybeObject* maybe_obj =
2073 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2074 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2075 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002076 return args[0]; // return TOS
2077}
2078
2079
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002080RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2081 NoHandleAllocation ha;
2082 RUNTIME_ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002083 CONVERT_ARG_CHECKED(JSFunction, function, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002084
2085 MaybeObject* maybe_name =
2086 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2087 String* name;
2088 if (!maybe_name->To(&name)) return maybe_name;
2089
2090 if (function->HasFastProperties()) {
2091 // Construct a new field descriptor with updated attributes.
2092 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2093 int index = instance_desc->Search(name);
2094 ASSERT(index != DescriptorArray::kNotFound);
2095 PropertyDetails details(instance_desc->GetDetails(index));
2096 CallbacksDescriptor new_desc(name,
2097 instance_desc->GetValue(index),
2098 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2099 details.index());
2100 // Construct a new field descriptors array containing the new descriptor.
2101 Object* descriptors_unchecked;
2102 { MaybeObject* maybe_descriptors_unchecked =
2103 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2104 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2105 return maybe_descriptors_unchecked;
2106 }
2107 }
2108 DescriptorArray* new_descriptors =
2109 DescriptorArray::cast(descriptors_unchecked);
2110 // Create a new map featuring the new field descriptors array.
2111 Object* map_unchecked;
2112 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2113 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2114 return maybe_map_unchecked;
2115 }
2116 }
2117 Map* new_map = Map::cast(map_unchecked);
2118 new_map->set_instance_descriptors(new_descriptors);
2119 function->set_map(new_map);
2120 } else { // Dictionary properties.
2121 // Directly manipulate the property details.
2122 int entry = function->property_dictionary()->FindEntry(name);
2123 ASSERT(entry != StringDictionary::kNotFound);
2124 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2125 PropertyDetails new_details(
2126 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2127 details.type(),
2128 details.index());
2129 function->property_dictionary()->DetailsAtPut(entry, new_details);
2130 }
2131 return function;
2132}
2133
2134
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002135RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002136 NoHandleAllocation ha;
2137 ASSERT(args.length() == 1);
2138
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002139 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002140 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002141}
2142
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002144RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002145 NoHandleAllocation ha;
2146 ASSERT(args.length() == 1);
2147
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002148 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002149 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002150}
2151
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002153RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002154 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002155 ASSERT(args.length() == 2);
2156
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002157 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002158 Handle<Object> code = args.at<Object>(1);
2159
2160 Handle<Context> context(target->context());
2161
2162 if (!code->IsNull()) {
2163 RUNTIME_ASSERT(code->IsJSFunction());
2164 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002165 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002166
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002167 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002168 return Failure::Exception();
2169 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002170 // Since we don't store the source for this we should never
2171 // optimize this.
2172 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002173 // Set the code, scope info, formal parameter count,
2174 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002175 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002176 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002177 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002178 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002179 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002180 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002181 // Set the source code of the target function to undefined.
2182 // SetCode is only used for built-in constructors like String,
2183 // Array, and Object, and some web code
2184 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002185 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002186 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002187 // Clear the optimization hints related to the compiled code as these are no
2188 // longer valid when the code is overwritten.
2189 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002190 context = Handle<Context>(fun->context());
2191
2192 // Make sure we get a fresh copy of the literal vector to avoid
2193 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002194 int number_of_literals = fun->NumberOfLiterals();
2195 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002196 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002197 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002198 // Insert the object, regexp and array functions in the literals
2199 // array prefix. These are the functions that will be used when
2200 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002201 literals->set(JSFunction::kLiteralGlobalContextIndex,
2202 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002203 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002204 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002205 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002206
2207 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2208 isolate->logger()->LogExistingFunction(
2209 shared, Handle<Code>(shared->code()));
2210 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002211 }
2212
2213 target->set_context(*context);
2214 return *target;
2215}
2216
2217
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002218RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002219 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002220 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002221 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002222 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002223 RUNTIME_ASSERT(num >= 0);
2224 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002225 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002226}
2227
2228
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002229MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2230 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002231 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002232 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002233 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002234 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002235 }
2236 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002237 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002238}
2239
2240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002241RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002242 NoHandleAllocation ha;
2243 ASSERT(args.length() == 2);
2244
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002245 CONVERT_ARG_CHECKED(String, subject, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002246 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002247 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002248
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002249 uint32_t i = 0;
2250 if (index->IsSmi()) {
2251 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002252 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002253 i = value;
2254 } else {
2255 ASSERT(index->IsHeapNumber());
2256 double value = HeapNumber::cast(index)->value();
2257 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002258 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002259
2260 // Flatten the string. If someone wants to get a char at an index
2261 // in a cons string, it is likely that more indices will be
2262 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002263 Object* flat;
2264 { MaybeObject* maybe_flat = subject->TryFlatten();
2265 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2266 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002267 subject = String::cast(flat);
2268
2269 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002270 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002271 }
2272
2273 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002274}
2275
2276
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002277RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002278 NoHandleAllocation ha;
2279 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002280 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002281}
2282
lrn@chromium.org25156de2010-04-06 13:10:27 +00002283
2284class FixedArrayBuilder {
2285 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002286 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2287 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002288 length_(0),
2289 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002290 // Require a non-zero initial size. Ensures that doubling the size to
2291 // extend the array will work.
2292 ASSERT(initial_capacity > 0);
2293 }
2294
2295 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2296 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002297 length_(0),
2298 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002299 // Require a non-zero initial size. Ensures that doubling the size to
2300 // extend the array will work.
2301 ASSERT(backing_store->length() > 0);
2302 }
2303
2304 bool HasCapacity(int elements) {
2305 int length = array_->length();
2306 int required_length = length_ + elements;
2307 return (length >= required_length);
2308 }
2309
2310 void EnsureCapacity(int elements) {
2311 int length = array_->length();
2312 int required_length = length_ + elements;
2313 if (length < required_length) {
2314 int new_length = length;
2315 do {
2316 new_length *= 2;
2317 } while (new_length < required_length);
2318 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002319 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002320 array_->CopyTo(0, *extended_array, 0, length_);
2321 array_ = extended_array;
2322 }
2323 }
2324
2325 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002326 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002327 ASSERT(length_ < capacity());
2328 array_->set(length_, value);
2329 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002330 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002331 }
2332
2333 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002334 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002335 ASSERT(length_ < capacity());
2336 array_->set(length_, value);
2337 length_++;
2338 }
2339
2340 Handle<FixedArray> array() {
2341 return array_;
2342 }
2343
2344 int length() {
2345 return length_;
2346 }
2347
2348 int capacity() {
2349 return array_->length();
2350 }
2351
2352 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002353 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002354 result_array->set_length(Smi::FromInt(length_));
2355 return result_array;
2356 }
2357
2358 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002359 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002360 target_array->set_length(Smi::FromInt(length_));
2361 return target_array;
2362 }
2363
2364 private:
2365 Handle<FixedArray> array_;
2366 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002367 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002368};
2369
2370
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002371// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002372const int kStringBuilderConcatHelperLengthBits = 11;
2373const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002374
2375template <typename schar>
2376static inline void StringBuilderConcatHelper(String*,
2377 schar*,
2378 FixedArray*,
2379 int);
2380
lrn@chromium.org25156de2010-04-06 13:10:27 +00002381typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2382 StringBuilderSubstringLength;
2383typedef BitField<int,
2384 kStringBuilderConcatHelperLengthBits,
2385 kStringBuilderConcatHelperPositionBits>
2386 StringBuilderSubstringPosition;
2387
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002388
2389class ReplacementStringBuilder {
2390 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002391 ReplacementStringBuilder(Heap* heap,
2392 Handle<String> subject,
2393 int estimated_part_count)
2394 : heap_(heap),
2395 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002396 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002397 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002398 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002399 // Require a non-zero initial size. Ensures that doubling the size to
2400 // extend the array will work.
2401 ASSERT(estimated_part_count > 0);
2402 }
2403
lrn@chromium.org25156de2010-04-06 13:10:27 +00002404 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2405 int from,
2406 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002407 ASSERT(from >= 0);
2408 int length = to - from;
2409 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002410 if (StringBuilderSubstringLength::is_valid(length) &&
2411 StringBuilderSubstringPosition::is_valid(from)) {
2412 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2413 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002414 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002415 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002416 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002417 builder->Add(Smi::FromInt(-length));
2418 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002419 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002420 }
2421
2422
2423 void EnsureCapacity(int elements) {
2424 array_builder_.EnsureCapacity(elements);
2425 }
2426
2427
2428 void AddSubjectSlice(int from, int to) {
2429 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002430 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002431 }
2432
2433
2434 void AddString(Handle<String> string) {
2435 int length = string->length();
2436 ASSERT(length > 0);
2437 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002438 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002439 is_ascii_ = false;
2440 }
2441 IncrementCharacterCount(length);
2442 }
2443
2444
2445 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002446 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002447 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002448 }
2449
2450 Handle<String> joined_string;
2451 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002452 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002453 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002454 char* char_buffer = seq->GetChars();
2455 StringBuilderConcatHelper(*subject_,
2456 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002457 *array_builder_.array(),
2458 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002459 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002460 } else {
2461 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002462 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002463 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002464 uc16* char_buffer = seq->GetChars();
2465 StringBuilderConcatHelper(*subject_,
2466 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002467 *array_builder_.array(),
2468 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002469 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002470 }
2471 return joined_string;
2472 }
2473
2474
2475 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002476 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002477 V8::FatalProcessOutOfMemory("String.replace result too large.");
2478 }
2479 character_count_ += by;
2480 }
2481
lrn@chromium.org25156de2010-04-06 13:10:27 +00002482 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002483 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002484 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002485
lrn@chromium.org25156de2010-04-06 13:10:27 +00002486 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002487 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2488 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002489 }
2490
2491
ager@chromium.org04921a82011-06-27 13:21:41 +00002492 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2493 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002494 }
2495
2496
2497 void AddElement(Object* element) {
2498 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002499 ASSERT(array_builder_.capacity() > array_builder_.length());
2500 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002501 }
2502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002503 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002504 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002505 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002506 int character_count_;
2507 bool is_ascii_;
2508};
2509
2510
2511class CompiledReplacement {
2512 public:
2513 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002514 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002515
2516 void Compile(Handle<String> replacement,
2517 int capture_count,
2518 int subject_length);
2519
2520 void Apply(ReplacementStringBuilder* builder,
2521 int match_from,
2522 int match_to,
2523 Handle<JSArray> last_match_info);
2524
2525 // Number of distinct parts of the replacement pattern.
2526 int parts() {
2527 return parts_.length();
2528 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002529
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002530 bool simple_hint() {
2531 return simple_hint_;
2532 }
2533
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002534 private:
2535 enum PartType {
2536 SUBJECT_PREFIX = 1,
2537 SUBJECT_SUFFIX,
2538 SUBJECT_CAPTURE,
2539 REPLACEMENT_SUBSTRING,
2540 REPLACEMENT_STRING,
2541
2542 NUMBER_OF_PART_TYPES
2543 };
2544
2545 struct ReplacementPart {
2546 static inline ReplacementPart SubjectMatch() {
2547 return ReplacementPart(SUBJECT_CAPTURE, 0);
2548 }
2549 static inline ReplacementPart SubjectCapture(int capture_index) {
2550 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2551 }
2552 static inline ReplacementPart SubjectPrefix() {
2553 return ReplacementPart(SUBJECT_PREFIX, 0);
2554 }
2555 static inline ReplacementPart SubjectSuffix(int subject_length) {
2556 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2557 }
2558 static inline ReplacementPart ReplacementString() {
2559 return ReplacementPart(REPLACEMENT_STRING, 0);
2560 }
2561 static inline ReplacementPart ReplacementSubString(int from, int to) {
2562 ASSERT(from >= 0);
2563 ASSERT(to > from);
2564 return ReplacementPart(-from, to);
2565 }
2566
2567 // If tag <= 0 then it is the negation of a start index of a substring of
2568 // the replacement pattern, otherwise it's a value from PartType.
2569 ReplacementPart(int tag, int data)
2570 : tag(tag), data(data) {
2571 // Must be non-positive or a PartType value.
2572 ASSERT(tag < NUMBER_OF_PART_TYPES);
2573 }
2574 // Either a value of PartType or a non-positive number that is
2575 // the negation of an index into the replacement string.
2576 int tag;
2577 // The data value's interpretation depends on the value of tag:
2578 // tag == SUBJECT_PREFIX ||
2579 // tag == SUBJECT_SUFFIX: data is unused.
2580 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2581 // tag == REPLACEMENT_SUBSTRING ||
2582 // tag == REPLACEMENT_STRING: data is index into array of substrings
2583 // of the replacement string.
2584 // tag <= 0: Temporary representation of the substring of the replacement
2585 // string ranging over -tag .. data.
2586 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2587 // substring objects.
2588 int data;
2589 };
2590
2591 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002592 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002593 Vector<Char> characters,
2594 int capture_count,
2595 int subject_length) {
2596 int length = characters.length();
2597 int last = 0;
2598 for (int i = 0; i < length; i++) {
2599 Char c = characters[i];
2600 if (c == '$') {
2601 int next_index = i + 1;
2602 if (next_index == length) { // No next character!
2603 break;
2604 }
2605 Char c2 = characters[next_index];
2606 switch (c2) {
2607 case '$':
2608 if (i > last) {
2609 // There is a substring before. Include the first "$".
2610 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2611 last = next_index + 1; // Continue after the second "$".
2612 } else {
2613 // Let the next substring start with the second "$".
2614 last = next_index;
2615 }
2616 i = next_index;
2617 break;
2618 case '`':
2619 if (i > last) {
2620 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2621 }
2622 parts->Add(ReplacementPart::SubjectPrefix());
2623 i = next_index;
2624 last = i + 1;
2625 break;
2626 case '\'':
2627 if (i > last) {
2628 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2629 }
2630 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2631 i = next_index;
2632 last = i + 1;
2633 break;
2634 case '&':
2635 if (i > last) {
2636 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2637 }
2638 parts->Add(ReplacementPart::SubjectMatch());
2639 i = next_index;
2640 last = i + 1;
2641 break;
2642 case '0':
2643 case '1':
2644 case '2':
2645 case '3':
2646 case '4':
2647 case '5':
2648 case '6':
2649 case '7':
2650 case '8':
2651 case '9': {
2652 int capture_ref = c2 - '0';
2653 if (capture_ref > capture_count) {
2654 i = next_index;
2655 continue;
2656 }
2657 int second_digit_index = next_index + 1;
2658 if (second_digit_index < length) {
2659 // Peek ahead to see if we have two digits.
2660 Char c3 = characters[second_digit_index];
2661 if ('0' <= c3 && c3 <= '9') { // Double digits.
2662 int double_digit_ref = capture_ref * 10 + c3 - '0';
2663 if (double_digit_ref <= capture_count) {
2664 next_index = second_digit_index;
2665 capture_ref = double_digit_ref;
2666 }
2667 }
2668 }
2669 if (capture_ref > 0) {
2670 if (i > last) {
2671 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2672 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002673 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002674 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2675 last = next_index + 1;
2676 }
2677 i = next_index;
2678 break;
2679 }
2680 default:
2681 i = next_index;
2682 break;
2683 }
2684 }
2685 }
2686 if (length > last) {
2687 if (last == 0) {
2688 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002689 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002690 } else {
2691 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2692 }
2693 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002694 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002695 }
2696
2697 ZoneList<ReplacementPart> parts_;
2698 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002699 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002700};
2701
2702
2703void CompiledReplacement::Compile(Handle<String> replacement,
2704 int capture_count,
2705 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002706 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002707 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002708 String::FlatContent content = replacement->GetFlatContent();
2709 ASSERT(content.IsFlat());
2710 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002711 simple_hint_ = ParseReplacementPattern(&parts_,
2712 content.ToAsciiVector(),
2713 capture_count,
2714 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002715 } else {
2716 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002717 simple_hint_ = ParseReplacementPattern(&parts_,
2718 content.ToUC16Vector(),
2719 capture_count,
2720 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002721 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002722 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002723 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002724 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002725 int substring_index = 0;
2726 for (int i = 0, n = parts_.length(); i < n; i++) {
2727 int tag = parts_[i].tag;
2728 if (tag <= 0) { // A replacement string slice.
2729 int from = -tag;
2730 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002731 replacement_substrings_.Add(
2732 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002733 parts_[i].tag = REPLACEMENT_SUBSTRING;
2734 parts_[i].data = substring_index;
2735 substring_index++;
2736 } else if (tag == REPLACEMENT_STRING) {
2737 replacement_substrings_.Add(replacement);
2738 parts_[i].data = substring_index;
2739 substring_index++;
2740 }
2741 }
2742}
2743
2744
2745void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2746 int match_from,
2747 int match_to,
2748 Handle<JSArray> last_match_info) {
2749 for (int i = 0, n = parts_.length(); i < n; i++) {
2750 ReplacementPart part = parts_[i];
2751 switch (part.tag) {
2752 case SUBJECT_PREFIX:
2753 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2754 break;
2755 case SUBJECT_SUFFIX: {
2756 int subject_length = part.data;
2757 if (match_to < subject_length) {
2758 builder->AddSubjectSlice(match_to, subject_length);
2759 }
2760 break;
2761 }
2762 case SUBJECT_CAPTURE: {
2763 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002764 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002765 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2766 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2767 if (from >= 0 && to > from) {
2768 builder->AddSubjectSlice(from, to);
2769 }
2770 break;
2771 }
2772 case REPLACEMENT_SUBSTRING:
2773 case REPLACEMENT_STRING:
2774 builder->AddString(replacement_substrings_[part.data]);
2775 break;
2776 default:
2777 UNREACHABLE();
2778 }
2779 }
2780}
2781
2782
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002783void FindAsciiStringIndices(Vector<const char> subject,
2784 char pattern,
2785 ZoneList<int>* indices,
2786 unsigned int limit) {
2787 ASSERT(limit > 0);
2788 // Collect indices of pattern in subject using memchr.
2789 // Stop after finding at most limit values.
2790 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2791 const char* subject_end = subject_start + subject.length();
2792 const char* pos = subject_start;
2793 while (limit > 0) {
2794 pos = reinterpret_cast<const char*>(
2795 memchr(pos, pattern, subject_end - pos));
2796 if (pos == NULL) return;
2797 indices->Add(static_cast<int>(pos - subject_start));
2798 pos++;
2799 limit--;
2800 }
2801}
2802
2803
2804template <typename SubjectChar, typename PatternChar>
2805void FindStringIndices(Isolate* isolate,
2806 Vector<const SubjectChar> subject,
2807 Vector<const PatternChar> pattern,
2808 ZoneList<int>* indices,
2809 unsigned int limit) {
2810 ASSERT(limit > 0);
2811 // Collect indices of pattern in subject.
2812 // Stop after finding at most limit values.
2813 int pattern_length = pattern.length();
2814 int index = 0;
2815 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2816 while (limit > 0) {
2817 index = search.Search(subject, index);
2818 if (index < 0) return;
2819 indices->Add(index);
2820 index += pattern_length;
2821 limit--;
2822 }
2823}
2824
2825
2826void FindStringIndicesDispatch(Isolate* isolate,
2827 String* subject,
2828 String* pattern,
2829 ZoneList<int>* indices,
2830 unsigned int limit) {
2831 {
2832 AssertNoAllocation no_gc;
2833 String::FlatContent subject_content = subject->GetFlatContent();
2834 String::FlatContent pattern_content = pattern->GetFlatContent();
2835 ASSERT(subject_content.IsFlat());
2836 ASSERT(pattern_content.IsFlat());
2837 if (subject_content.IsAscii()) {
2838 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2839 if (pattern_content.IsAscii()) {
2840 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2841 if (pattern_vector.length() == 1) {
2842 FindAsciiStringIndices(subject_vector,
2843 pattern_vector[0],
2844 indices,
2845 limit);
2846 } else {
2847 FindStringIndices(isolate,
2848 subject_vector,
2849 pattern_vector,
2850 indices,
2851 limit);
2852 }
2853 } else {
2854 FindStringIndices(isolate,
2855 subject_vector,
2856 pattern_content.ToUC16Vector(),
2857 indices,
2858 limit);
2859 }
2860 } else {
2861 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002862 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002863 FindStringIndices(isolate,
2864 subject_vector,
2865 pattern_content.ToAsciiVector(),
2866 indices,
2867 limit);
2868 } else {
2869 FindStringIndices(isolate,
2870 subject_vector,
2871 pattern_content.ToUC16Vector(),
2872 indices,
2873 limit);
2874 }
2875 }
2876 }
2877}
2878
2879
2880template<typename ResultSeqString>
2881MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2882 Isolate* isolate,
2883 Handle<String> subject,
2884 Handle<JSRegExp> pattern_regexp,
2885 Handle<String> replacement) {
2886 ASSERT(subject->IsFlat());
2887 ASSERT(replacement->IsFlat());
2888
2889 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2890 ZoneList<int> indices(8);
2891 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2892 String* pattern =
2893 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2894 int subject_len = subject->length();
2895 int pattern_len = pattern->length();
2896 int replacement_len = replacement->length();
2897
2898 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2899
2900 int matches = indices.length();
2901 if (matches == 0) return *subject;
2902
2903 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2904 int subject_pos = 0;
2905 int result_pos = 0;
2906
2907 Handle<ResultSeqString> result;
2908 if (ResultSeqString::kHasAsciiEncoding) {
2909 result = Handle<ResultSeqString>::cast(
2910 isolate->factory()->NewRawAsciiString(result_len));
2911 } else {
2912 result = Handle<ResultSeqString>::cast(
2913 isolate->factory()->NewRawTwoByteString(result_len));
2914 }
2915
2916 for (int i = 0; i < matches; i++) {
2917 // Copy non-matched subject content.
2918 if (subject_pos < indices.at(i)) {
2919 String::WriteToFlat(*subject,
2920 result->GetChars() + result_pos,
2921 subject_pos,
2922 indices.at(i));
2923 result_pos += indices.at(i) - subject_pos;
2924 }
2925
2926 // Replace match.
2927 if (replacement_len > 0) {
2928 String::WriteToFlat(*replacement,
2929 result->GetChars() + result_pos,
2930 0,
2931 replacement_len);
2932 result_pos += replacement_len;
2933 }
2934
2935 subject_pos = indices.at(i) + pattern_len;
2936 }
2937 // Add remaining subject content at the end.
2938 if (subject_pos < subject_len) {
2939 String::WriteToFlat(*subject,
2940 result->GetChars() + result_pos,
2941 subject_pos,
2942 subject_len);
2943 }
2944 return *result;
2945}
2946
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002947
lrn@chromium.org303ada72010-10-27 09:33:13 +00002948MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002949 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002950 String* subject,
2951 JSRegExp* regexp,
2952 String* replacement,
2953 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002954 ASSERT(subject->IsFlat());
2955 ASSERT(replacement->IsFlat());
2956
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002957 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002958
2959 int length = subject->length();
2960 Handle<String> subject_handle(subject);
2961 Handle<JSRegExp> regexp_handle(regexp);
2962 Handle<String> replacement_handle(replacement);
2963 Handle<JSArray> last_match_info_handle(last_match_info);
2964 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2965 subject_handle,
2966 0,
2967 last_match_info_handle);
2968 if (match.is_null()) {
2969 return Failure::Exception();
2970 }
2971 if (match->IsNull()) {
2972 return *subject_handle;
2973 }
2974
2975 int capture_count = regexp_handle->CaptureCount();
2976
2977 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002978 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002979 CompiledReplacement compiled_replacement;
2980 compiled_replacement.Compile(replacement_handle,
2981 capture_count,
2982 length);
2983
2984 bool is_global = regexp_handle->GetFlags().is_global();
2985
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002986 // Shortcut for simple non-regexp global replacements
2987 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002988 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002989 compiled_replacement.simple_hint()) {
2990 if (subject_handle->HasOnlyAsciiChars() &&
2991 replacement_handle->HasOnlyAsciiChars()) {
2992 return StringReplaceStringWithString<SeqAsciiString>(
2993 isolate, subject_handle, regexp_handle, replacement_handle);
2994 } else {
2995 return StringReplaceStringWithString<SeqTwoByteString>(
2996 isolate, subject_handle, regexp_handle, replacement_handle);
2997 }
2998 }
2999
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003000 // Guessing the number of parts that the final result string is built
3001 // from. Global regexps can match any number of times, so we guess
3002 // conservatively.
3003 int expected_parts =
3004 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003005 ReplacementStringBuilder builder(isolate->heap(),
3006 subject_handle,
3007 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003008
3009 // Index of end of last match.
3010 int prev = 0;
3011
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003012 // Number of parts added by compiled replacement plus preceeding
3013 // string and possibly suffix after last match. It is possible for
3014 // all components to use two elements when encoded as two smis.
3015 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003016 bool matched = true;
3017 do {
3018 ASSERT(last_match_info_handle->HasFastElements());
3019 // Increase the capacity of the builder before entering local handle-scope,
3020 // so its internal buffer can safely allocate a new handle if it grows.
3021 builder.EnsureCapacity(parts_added_per_loop);
3022
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003023 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003024 int start, end;
3025 {
3026 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003027 FixedArray* match_info_array =
3028 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003029
3030 ASSERT_EQ(capture_count * 2 + 2,
3031 RegExpImpl::GetLastCaptureCount(match_info_array));
3032 start = RegExpImpl::GetCapture(match_info_array, 0);
3033 end = RegExpImpl::GetCapture(match_info_array, 1);
3034 }
3035
3036 if (prev < start) {
3037 builder.AddSubjectSlice(prev, start);
3038 }
3039 compiled_replacement.Apply(&builder,
3040 start,
3041 end,
3042 last_match_info_handle);
3043 prev = end;
3044
3045 // Only continue checking for global regexps.
3046 if (!is_global) break;
3047
3048 // Continue from where the match ended, unless it was an empty match.
3049 int next = end;
3050 if (start == end) {
3051 next = end + 1;
3052 if (next > length) break;
3053 }
3054
3055 match = RegExpImpl::Exec(regexp_handle,
3056 subject_handle,
3057 next,
3058 last_match_info_handle);
3059 if (match.is_null()) {
3060 return Failure::Exception();
3061 }
3062 matched = !match->IsNull();
3063 } while (matched);
3064
3065 if (prev < length) {
3066 builder.AddSubjectSlice(prev, length);
3067 }
3068
3069 return *(builder.ToString());
3070}
3071
3072
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003073template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003074MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003075 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003076 String* subject,
3077 JSRegExp* regexp,
3078 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003079 ASSERT(subject->IsFlat());
3080
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003081 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003082
3083 Handle<String> subject_handle(subject);
3084 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003085
3086 // Shortcut for simple non-regexp global replacements
3087 if (regexp_handle->GetFlags().is_global() &&
3088 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3089 Handle<String> empty_string_handle(HEAP->empty_string());
3090 if (subject_handle->HasOnlyAsciiChars()) {
3091 return StringReplaceStringWithString<SeqAsciiString>(
3092 isolate, subject_handle, regexp_handle, empty_string_handle);
3093 } else {
3094 return StringReplaceStringWithString<SeqTwoByteString>(
3095 isolate, subject_handle, regexp_handle, empty_string_handle);
3096 }
3097 }
3098
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003099 Handle<JSArray> last_match_info_handle(last_match_info);
3100 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3101 subject_handle,
3102 0,
3103 last_match_info_handle);
3104 if (match.is_null()) return Failure::Exception();
3105 if (match->IsNull()) return *subject_handle;
3106
3107 ASSERT(last_match_info_handle->HasFastElements());
3108
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003109 int start, end;
3110 {
3111 AssertNoAllocation match_info_array_is_not_in_a_handle;
3112 FixedArray* match_info_array =
3113 FixedArray::cast(last_match_info_handle->elements());
3114
3115 start = RegExpImpl::GetCapture(match_info_array, 0);
3116 end = RegExpImpl::GetCapture(match_info_array, 1);
3117 }
3118
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003119 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003120 int new_length = length - (end - start);
3121 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003122 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003123 }
3124 Handle<ResultSeqString> answer;
3125 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003126 answer = Handle<ResultSeqString>::cast(
3127 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003128 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003129 answer = Handle<ResultSeqString>::cast(
3130 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003131 }
3132
3133 // If the regexp isn't global, only match once.
3134 if (!regexp_handle->GetFlags().is_global()) {
3135 if (start > 0) {
3136 String::WriteToFlat(*subject_handle,
3137 answer->GetChars(),
3138 0,
3139 start);
3140 }
3141 if (end < length) {
3142 String::WriteToFlat(*subject_handle,
3143 answer->GetChars() + start,
3144 end,
3145 length);
3146 }
3147 return *answer;
3148 }
3149
3150 int prev = 0; // Index of end of last match.
3151 int next = 0; // Start of next search (prev unless last match was empty).
3152 int position = 0;
3153
3154 do {
3155 if (prev < start) {
3156 // Add substring subject[prev;start] to answer string.
3157 String::WriteToFlat(*subject_handle,
3158 answer->GetChars() + position,
3159 prev,
3160 start);
3161 position += start - prev;
3162 }
3163 prev = end;
3164 next = end;
3165 // Continue from where the match ended, unless it was an empty match.
3166 if (start == end) {
3167 next++;
3168 if (next > length) break;
3169 }
3170 match = RegExpImpl::Exec(regexp_handle,
3171 subject_handle,
3172 next,
3173 last_match_info_handle);
3174 if (match.is_null()) return Failure::Exception();
3175 if (match->IsNull()) break;
3176
3177 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003178 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003179 {
3180 AssertNoAllocation match_info_array_is_not_in_a_handle;
3181 FixedArray* match_info_array =
3182 FixedArray::cast(last_match_info_handle->elements());
3183 start = RegExpImpl::GetCapture(match_info_array, 0);
3184 end = RegExpImpl::GetCapture(match_info_array, 1);
3185 }
3186 } while (true);
3187
3188 if (prev < length) {
3189 // Add substring subject[prev;length] to answer string.
3190 String::WriteToFlat(*subject_handle,
3191 answer->GetChars() + position,
3192 prev,
3193 length);
3194 position += length - prev;
3195 }
3196
3197 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003198 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003199 }
3200
3201 // Shorten string and fill
3202 int string_size = ResultSeqString::SizeFor(position);
3203 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3204 int delta = allocated_string_size - string_size;
3205
3206 answer->set_length(position);
3207 if (delta == 0) return *answer;
3208
3209 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003210 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003211 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003212 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003213 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003214
3215 return *answer;
3216}
3217
3218
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003219RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003220 ASSERT(args.length() == 4);
3221
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003222 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003223 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003224 Object* flat_subject;
3225 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3226 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3227 return maybe_flat_subject;
3228 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003229 }
3230 subject = String::cast(flat_subject);
3231 }
3232
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003233 CONVERT_ARG_CHECKED(String, replacement, 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003234 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003235 Object* flat_replacement;
3236 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3237 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3238 return maybe_flat_replacement;
3239 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003240 }
3241 replacement = String::cast(flat_replacement);
3242 }
3243
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003244 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3245 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003246
3247 ASSERT(last_match_info->HasFastElements());
3248
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003249 if (replacement->length() == 0) {
3250 if (subject->HasOnlyAsciiChars()) {
3251 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003252 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003253 } else {
3254 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003255 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003256 }
3257 }
3258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003259 return StringReplaceRegExpWithString(isolate,
3260 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003261 regexp,
3262 replacement,
3263 last_match_info);
3264}
3265
3266
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003267Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3268 Handle<String> subject,
3269 Handle<String> search,
3270 Handle<String> replace,
3271 bool* found,
3272 int recursion_limit) {
3273 if (recursion_limit == 0) return Handle<String>::null();
3274 if (subject->IsConsString()) {
3275 ConsString* cons = ConsString::cast(*subject);
3276 Handle<String> first = Handle<String>(cons->first());
3277 Handle<String> second = Handle<String>(cons->second());
3278 Handle<String> new_first =
3279 StringReplaceOneCharWithString(isolate,
3280 first,
3281 search,
3282 replace,
3283 found,
3284 recursion_limit - 1);
3285 if (*found) return isolate->factory()->NewConsString(new_first, second);
3286 if (new_first.is_null()) return new_first;
3287
3288 Handle<String> new_second =
3289 StringReplaceOneCharWithString(isolate,
3290 second,
3291 search,
3292 replace,
3293 found,
3294 recursion_limit - 1);
3295 if (*found) return isolate->factory()->NewConsString(first, new_second);
3296 if (new_second.is_null()) return new_second;
3297
3298 return subject;
3299 } else {
3300 int index = StringMatch(isolate, subject, search, 0);
3301 if (index == -1) return subject;
3302 *found = true;
3303 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3304 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3305 Handle<String> second =
3306 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3307 return isolate->factory()->NewConsString(cons1, second);
3308 }
3309}
3310
3311
3312RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3313 ASSERT(args.length() == 3);
3314 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003315 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3316 CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
3317 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003318
3319 // If the cons string tree is too deep, we simply abort the recursion and
3320 // retry with a flattened subject string.
3321 const int kRecursionLimit = 0x1000;
3322 bool found = false;
3323 Handle<String> result =
3324 Runtime::StringReplaceOneCharWithString(isolate,
3325 subject,
3326 search,
3327 replace,
3328 &found,
3329 kRecursionLimit);
3330 if (!result.is_null()) return *result;
3331 return *Runtime::StringReplaceOneCharWithString(isolate,
3332 FlattenGetString(subject),
3333 search,
3334 replace,
3335 &found,
3336 kRecursionLimit);
3337}
3338
3339
ager@chromium.org7c537e22008-10-16 08:43:32 +00003340// Perform string match of pattern on subject, starting at start index.
3341// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003342// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003343int Runtime::StringMatch(Isolate* isolate,
3344 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003345 Handle<String> pat,
3346 int start_index) {
3347 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003348 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003349
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003350 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003351 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003352
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003353 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003354 if (start_index + pattern_length > subject_length) return -1;
3355
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003356 if (!sub->IsFlat()) FlattenString(sub);
3357 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003358
ager@chromium.org7c537e22008-10-16 08:43:32 +00003359 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003360 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003361 String::FlatContent seq_sub = sub->GetFlatContent();
3362 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003363
ager@chromium.org7c537e22008-10-16 08:43:32 +00003364 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003365 if (seq_pat.IsAscii()) {
3366 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3367 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003368 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003369 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003370 pat_vector,
3371 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003372 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003373 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003374 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003375 pat_vector,
3376 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003377 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003378 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3379 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003380 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003381 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003382 pat_vector,
3383 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003384 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003385 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003386 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003387 pat_vector,
3388 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003389}
3390
3391
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003392RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003393 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003394 ASSERT(args.length() == 3);
3395
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003396 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3397 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003398
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003399 Object* index = args[2];
3400 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003401 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003402
ager@chromium.org870a0b62008-11-04 11:43:05 +00003403 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003404 int position =
3405 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003406 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003407}
3408
3409
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003410template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003411static int StringMatchBackwards(Vector<const schar> subject,
3412 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003413 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003414 int pattern_length = pattern.length();
3415 ASSERT(pattern_length >= 1);
3416 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003417
3418 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003419 for (int i = 0; i < pattern_length; i++) {
3420 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003421 if (c > String::kMaxAsciiCharCode) {
3422 return -1;
3423 }
3424 }
3425 }
3426
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003427 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003428 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003429 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003430 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003431 while (j < pattern_length) {
3432 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003433 break;
3434 }
3435 j++;
3436 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003437 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003438 return i;
3439 }
3440 }
3441 return -1;
3442}
3443
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003444RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003445 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003446 ASSERT(args.length() == 3);
3447
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003448 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3449 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003450
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003451 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003452 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003453 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003454
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003455 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003456 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003457
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003458 if (start_index + pat_length > sub_length) {
3459 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003460 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003461
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003462 if (pat_length == 0) {
3463 return Smi::FromInt(start_index);
3464 }
3465
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003466 if (!sub->IsFlat()) FlattenString(sub);
3467 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003468
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003469 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003470 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3471
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003472 String::FlatContent sub_content = sub->GetFlatContent();
3473 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003474
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003475 if (pat_content.IsAscii()) {
3476 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3477 if (sub_content.IsAscii()) {
3478 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003479 pat_vector,
3480 start_index);
3481 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003482 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003483 pat_vector,
3484 start_index);
3485 }
3486 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003487 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3488 if (sub_content.IsAscii()) {
3489 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003490 pat_vector,
3491 start_index);
3492 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003493 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003494 pat_vector,
3495 start_index);
3496 }
3497 }
3498
3499 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003500}
3501
3502
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003503RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003504 NoHandleAllocation ha;
3505 ASSERT(args.length() == 2);
3506
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003507 CONVERT_ARG_CHECKED(String, str1, 0);
3508 CONVERT_ARG_CHECKED(String, str2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003509
3510 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003511 int str1_length = str1->length();
3512 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003513
3514 // Decide trivial cases without flattening.
3515 if (str1_length == 0) {
3516 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3517 return Smi::FromInt(-str2_length);
3518 } else {
3519 if (str2_length == 0) return Smi::FromInt(str1_length);
3520 }
3521
3522 int end = str1_length < str2_length ? str1_length : str2_length;
3523
3524 // No need to flatten if we are going to find the answer on the first
3525 // character. At this point we know there is at least one character
3526 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003527 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003528 if (d != 0) return Smi::FromInt(d);
3529
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003530 str1->TryFlatten();
3531 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003532
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003533 StringInputBuffer& buf1 =
3534 *isolate->runtime_state()->string_locale_compare_buf1();
3535 StringInputBuffer& buf2 =
3536 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003537
3538 buf1.Reset(str1);
3539 buf2.Reset(str2);
3540
3541 for (int i = 0; i < end; i++) {
3542 uint16_t char1 = buf1.GetNext();
3543 uint16_t char2 = buf2.GetNext();
3544 if (char1 != char2) return Smi::FromInt(char1 - char2);
3545 }
3546
3547 return Smi::FromInt(str1_length - str2_length);
3548}
3549
3550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003551RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003552 NoHandleAllocation ha;
3553 ASSERT(args.length() == 3);
3554
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003555 CONVERT_ARG_CHECKED(String, value, 0);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003556 int start, end;
3557 // We have a fast integer-only case here to avoid a conversion to double in
3558 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003559 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3560 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3561 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3562 start = from_number;
3563 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003564 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003565 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3566 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003567 start = FastD2I(from_number);
3568 end = FastD2I(to_number);
3569 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003570 RUNTIME_ASSERT(end >= start);
3571 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003572 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003573 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003574 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003575}
3576
3577
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003578RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003579 ASSERT_EQ(3, args.length());
3580
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003581 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3582 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
3583 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
ager@chromium.org41826e72009-03-30 13:30:57 +00003584 HandleScope handles;
3585
3586 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3587
3588 if (match.is_null()) {
3589 return Failure::Exception();
3590 }
3591 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003592 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003593 }
3594 int length = subject->length();
3595
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003596 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003597 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003598 int start;
3599 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003600 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003601 {
3602 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003603 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003604 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3605 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3606 }
3607 offsets.Add(start);
3608 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003609 if (start == end) if (++end > length) break;
3610 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003611 if (match.is_null()) {
3612 return Failure::Exception();
3613 }
3614 } while (!match->IsNull());
3615 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003616 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003617 Handle<String> substring = isolate->factory()->
3618 NewSubString(subject, offsets.at(0), offsets.at(1));
3619 elements->set(0, *substring);
3620 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003621 int from = offsets.at(i * 2);
3622 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003623 Handle<String> substring = isolate->factory()->
3624 NewProperSubString(subject, from, to);
3625 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003626 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003627 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003628 result->set_length(Smi::FromInt(matches));
3629 return *result;
3630}
3631
3632
lrn@chromium.org25156de2010-04-06 13:10:27 +00003633// Two smis before and after the match, for very long strings.
3634const int kMaxBuilderEntriesPerRegExpMatch = 5;
3635
3636
3637static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3638 Handle<JSArray> last_match_info,
3639 int match_start,
3640 int match_end) {
3641 // Fill last_match_info with a single capture.
3642 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3643 AssertNoAllocation no_gc;
3644 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3645 RegExpImpl::SetLastCaptureCount(elements, 2);
3646 RegExpImpl::SetLastInput(elements, *subject);
3647 RegExpImpl::SetLastSubject(elements, *subject);
3648 RegExpImpl::SetCapture(elements, 0, match_start);
3649 RegExpImpl::SetCapture(elements, 1, match_end);
3650}
3651
3652
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003653template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003654static bool SearchStringMultiple(Isolate* isolate,
3655 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003656 Vector<const PatternChar> pattern,
3657 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003658 FixedArrayBuilder* builder,
3659 int* match_pos) {
3660 int pos = *match_pos;
3661 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003662 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003663 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003664 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003665 while (pos <= max_search_start) {
3666 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3667 *match_pos = pos;
3668 return false;
3669 }
3670 // Position of end of previous match.
3671 int match_end = pos + pattern_length;
3672 int new_pos = search.Search(subject, match_end);
3673 if (new_pos >= 0) {
3674 // A match.
3675 if (new_pos > match_end) {
3676 ReplacementStringBuilder::AddSubjectSlice(builder,
3677 match_end,
3678 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003679 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003680 pos = new_pos;
3681 builder->Add(pattern_string);
3682 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003683 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003684 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003685 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003686
lrn@chromium.org25156de2010-04-06 13:10:27 +00003687 if (pos < max_search_start) {
3688 ReplacementStringBuilder::AddSubjectSlice(builder,
3689 pos + pattern_length,
3690 subject_length);
3691 }
3692 *match_pos = pos;
3693 return true;
3694}
3695
3696
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003697static bool SearchStringMultiple(Isolate* isolate,
3698 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003699 Handle<String> pattern,
3700 Handle<JSArray> last_match_info,
3701 FixedArrayBuilder* builder) {
3702 ASSERT(subject->IsFlat());
3703 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003704
3705 // Treating as if a previous match was before first character.
3706 int match_pos = -pattern->length();
3707
3708 for (;;) { // Break when search complete.
3709 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3710 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003711 String::FlatContent subject_content = subject->GetFlatContent();
3712 String::FlatContent pattern_content = pattern->GetFlatContent();
3713 if (subject_content.IsAscii()) {
3714 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3715 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003716 if (SearchStringMultiple(isolate,
3717 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003718 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003719 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003720 builder,
3721 &match_pos)) break;
3722 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003723 if (SearchStringMultiple(isolate,
3724 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003725 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003726 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003727 builder,
3728 &match_pos)) break;
3729 }
3730 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003731 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3732 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003733 if (SearchStringMultiple(isolate,
3734 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003735 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003736 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003737 builder,
3738 &match_pos)) break;
3739 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003740 if (SearchStringMultiple(isolate,
3741 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003742 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003743 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003744 builder,
3745 &match_pos)) break;
3746 }
3747 }
3748 }
3749
3750 if (match_pos >= 0) {
3751 SetLastMatchInfoNoCaptures(subject,
3752 last_match_info,
3753 match_pos,
3754 match_pos + pattern->length());
3755 return true;
3756 }
3757 return false; // No matches at all.
3758}
3759
3760
3761static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003762 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003763 Handle<String> subject,
3764 Handle<JSRegExp> regexp,
3765 Handle<JSArray> last_match_array,
3766 FixedArrayBuilder* builder) {
3767 ASSERT(subject->IsFlat());
3768 int match_start = -1;
3769 int match_end = 0;
3770 int pos = 0;
3771 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3772 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3773
3774 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003775 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003776 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003777 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003778
3779 for (;;) { // Break on failure, return on exception.
3780 RegExpImpl::IrregexpResult result =
3781 RegExpImpl::IrregexpExecOnce(regexp,
3782 subject,
3783 pos,
3784 register_vector);
3785 if (result == RegExpImpl::RE_SUCCESS) {
3786 match_start = register_vector[0];
3787 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3788 if (match_end < match_start) {
3789 ReplacementStringBuilder::AddSubjectSlice(builder,
3790 match_end,
3791 match_start);
3792 }
3793 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003794 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003795 if (!first) {
3796 builder->Add(*isolate->factory()->NewProperSubString(subject,
3797 match_start,
3798 match_end));
3799 } else {
3800 builder->Add(*isolate->factory()->NewSubString(subject,
3801 match_start,
3802 match_end));
3803 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003804 if (match_start != match_end) {
3805 pos = match_end;
3806 } else {
3807 pos = match_end + 1;
3808 if (pos > subject_length) break;
3809 }
3810 } else if (result == RegExpImpl::RE_FAILURE) {
3811 break;
3812 } else {
3813 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3814 return result;
3815 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003816 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003817 }
3818
3819 if (match_start >= 0) {
3820 if (match_end < subject_length) {
3821 ReplacementStringBuilder::AddSubjectSlice(builder,
3822 match_end,
3823 subject_length);
3824 }
3825 SetLastMatchInfoNoCaptures(subject,
3826 last_match_array,
3827 match_start,
3828 match_end);
3829 return RegExpImpl::RE_SUCCESS;
3830 } else {
3831 return RegExpImpl::RE_FAILURE; // No matches at all.
3832 }
3833}
3834
3835
3836static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003837 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003838 Handle<String> subject,
3839 Handle<JSRegExp> regexp,
3840 Handle<JSArray> last_match_array,
3841 FixedArrayBuilder* builder) {
3842
3843 ASSERT(subject->IsFlat());
3844 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3845 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3846
3847 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003848 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003849
3850 RegExpImpl::IrregexpResult result =
3851 RegExpImpl::IrregexpExecOnce(regexp,
3852 subject,
3853 0,
3854 register_vector);
3855
3856 int capture_count = regexp->CaptureCount();
3857 int subject_length = subject->length();
3858
3859 // Position to search from.
3860 int pos = 0;
3861 // End of previous match. Differs from pos if match was empty.
3862 int match_end = 0;
3863 if (result == RegExpImpl::RE_SUCCESS) {
3864 // Need to keep a copy of the previous match for creating last_match_info
3865 // at the end, so we have two vectors that we swap between.
3866 OffsetsVector registers2(required_registers);
3867 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003868 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003869 do {
3870 int match_start = register_vector[0];
3871 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3872 if (match_end < match_start) {
3873 ReplacementStringBuilder::AddSubjectSlice(builder,
3874 match_end,
3875 match_start);
3876 }
3877 match_end = register_vector[1];
3878
3879 {
3880 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003881 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003882 // Arguments array to replace function is match, captures, index and
3883 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003884 Handle<FixedArray> elements =
3885 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003886 Handle<String> match;
3887 if (!first) {
3888 match = isolate->factory()->NewProperSubString(subject,
3889 match_start,
3890 match_end);
3891 } else {
3892 match = isolate->factory()->NewSubString(subject,
3893 match_start,
3894 match_end);
3895 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003896 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003897 for (int i = 1; i <= capture_count; i++) {
3898 int start = register_vector[i * 2];
3899 if (start >= 0) {
3900 int end = register_vector[i * 2 + 1];
3901 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003902 Handle<String> substring;
3903 if (!first) {
3904 substring = isolate->factory()->NewProperSubString(subject,
3905 start,
3906 end);
3907 } else {
3908 substring = isolate->factory()->NewSubString(subject, start, end);
3909 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003910 elements->set(i, *substring);
3911 } else {
3912 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003913 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003914 }
3915 }
3916 elements->set(capture_count + 1, Smi::FromInt(match_start));
3917 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003918 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003919 }
3920 // Swap register vectors, so the last successful match is in
3921 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003922 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003923 prev_register_vector = register_vector;
3924 register_vector = tmp;
3925
3926 if (match_end > match_start) {
3927 pos = match_end;
3928 } else {
3929 pos = match_end + 1;
3930 if (pos > subject_length) {
3931 break;
3932 }
3933 }
3934
3935 result = RegExpImpl::IrregexpExecOnce(regexp,
3936 subject,
3937 pos,
3938 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003939 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003940 } while (result == RegExpImpl::RE_SUCCESS);
3941
3942 if (result != RegExpImpl::RE_EXCEPTION) {
3943 // Finished matching, with at least one match.
3944 if (match_end < subject_length) {
3945 ReplacementStringBuilder::AddSubjectSlice(builder,
3946 match_end,
3947 subject_length);
3948 }
3949
3950 int last_match_capture_count = (capture_count + 1) * 2;
3951 int last_match_array_size =
3952 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3953 last_match_array->EnsureSize(last_match_array_size);
3954 AssertNoAllocation no_gc;
3955 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3956 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3957 RegExpImpl::SetLastSubject(elements, *subject);
3958 RegExpImpl::SetLastInput(elements, *subject);
3959 for (int i = 0; i < last_match_capture_count; i++) {
3960 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3961 }
3962 return RegExpImpl::RE_SUCCESS;
3963 }
3964 }
3965 // No matches at all, return failure or exception result directly.
3966 return result;
3967}
3968
3969
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003970RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003971 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003972 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003973
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003974 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003975 if (!subject->IsFlat()) FlattenString(subject);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003976 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
3977 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
3978 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003979
3980 ASSERT(last_match_info->HasFastElements());
3981 ASSERT(regexp->GetFlags().is_global());
3982 Handle<FixedArray> result_elements;
3983 if (result_array->HasFastElements()) {
3984 result_elements =
3985 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003986 }
3987 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003988 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003989 }
3990 FixedArrayBuilder builder(result_elements);
3991
3992 if (regexp->TypeTag() == JSRegExp::ATOM) {
3993 Handle<String> pattern(
3994 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003995 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003996 if (SearchStringMultiple(isolate, subject, pattern,
3997 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003998 return *builder.ToJSArray(result_array);
3999 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004000 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004001 }
4002
4003 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
4004
4005 RegExpImpl::IrregexpResult result;
4006 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004007 result = SearchRegExpNoCaptureMultiple(isolate,
4008 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00004009 regexp,
4010 last_match_info,
4011 &builder);
4012 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004013 result = SearchRegExpMultiple(isolate,
4014 subject,
4015 regexp,
4016 last_match_info,
4017 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004018 }
4019 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004020 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004021 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
4022 return Failure::Exception();
4023}
4024
4025
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004026RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004027 NoHandleAllocation ha;
4028 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004029 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004030 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004031
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004032 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004033 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004034 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004035 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004036 // Character array used for conversion.
4037 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004038 return isolate->heap()->
4039 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004040 }
4041 }
4042
4043 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004044 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004045 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004046 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004047 }
4048 if (isinf(value)) {
4049 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004050 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004051 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004052 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004053 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004055 MaybeObject* result =
4056 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004057 DeleteArray(str);
4058 return result;
4059}
4060
4061
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004062RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004063 NoHandleAllocation ha;
4064 ASSERT(args.length() == 2);
4065
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004066 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004067 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004068 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004069 }
4070 if (isinf(value)) {
4071 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004072 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004073 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004074 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004075 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004076 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004077 int f = FastD2I(f_number);
4078 RUNTIME_ASSERT(f >= 0);
4079 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004080 MaybeObject* res =
4081 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004082 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004083 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004084}
4085
4086
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004087RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 NoHandleAllocation ha;
4089 ASSERT(args.length() == 2);
4090
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004091 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004092 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004093 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004094 }
4095 if (isinf(value)) {
4096 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004097 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004099 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004100 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004101 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004102 int f = FastD2I(f_number);
4103 RUNTIME_ASSERT(f >= -1 && f <= 20);
4104 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004105 MaybeObject* res =
4106 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004107 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004108 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109}
4110
4111
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004112RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004113 NoHandleAllocation ha;
4114 ASSERT(args.length() == 2);
4115
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004116 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004117 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004118 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004119 }
4120 if (isinf(value)) {
4121 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004122 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004123 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004124 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004125 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004126 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004127 int f = FastD2I(f_number);
4128 RUNTIME_ASSERT(f >= 1 && f <= 21);
4129 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004130 MaybeObject* res =
4131 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004132 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004133 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004134}
4135
4136
4137// Returns a single character string where first character equals
4138// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004139static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004140 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004141 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004142 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004143 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004144 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004145 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004146}
4147
4148
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004149MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4150 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004151 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004152 // Handle [] indexing on Strings
4153 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004154 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4155 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004156 }
4157
4158 // Handle [] indexing on String objects
4159 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004160 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4161 Handle<Object> result =
4162 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4163 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164 }
4165
4166 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004167 return object->GetPrototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004168 }
4169
4170 return object->GetElement(index);
4171}
4172
4173
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004174MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4175 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004176 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004177 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004178
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004179 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004180 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004181 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004182 isolate->factory()->NewTypeError("non_object_property_load",
4183 HandleVector(args, 2));
4184 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004185 }
4186
4187 // Check if the given key is an array index.
4188 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004189 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004190 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004191 }
4192
4193 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004194 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004195 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004196 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004197 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004198 bool has_pending_exception = false;
4199 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004200 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004201 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004202 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004203 }
4204
ager@chromium.org32912102009-01-16 10:38:43 +00004205 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004206 // the element if so.
4207 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004208 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004209 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004210 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004211 }
4212}
4213
4214
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004215RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004216 NoHandleAllocation ha;
4217 ASSERT(args.length() == 2);
4218
4219 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004220 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004221
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004222 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004223}
4224
4225
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004226// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004227RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004228 NoHandleAllocation ha;
4229 ASSERT(args.length() == 2);
4230
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004231 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004232 // itself.
4233 //
4234 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004235 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004236 // global proxy object never has properties. This is the case
4237 // because the global proxy object forwards everything to its hidden
4238 // prototype including local lookups.
4239 //
4240 // Additionally, we need to make sure that we do not cache results
4241 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004242 if (args[0]->IsJSObject()) {
4243 if (!args[0]->IsJSGlobalProxy() &&
4244 !args[0]->IsAccessCheckNeeded() &&
4245 args[1]->IsString()) {
4246 JSObject* receiver = JSObject::cast(args[0]);
4247 String* key = String::cast(args[1]);
4248 if (receiver->HasFastProperties()) {
4249 // Attempt to use lookup cache.
4250 Map* receiver_map = receiver->map();
4251 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4252 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4253 if (offset != -1) {
4254 Object* value = receiver->FastPropertyAt(offset);
4255 return value->IsTheHole()
4256 ? isolate->heap()->undefined_value()
4257 : value;
4258 }
4259 // Lookup cache miss. Perform lookup and update the cache if
4260 // appropriate.
4261 LookupResult result(isolate);
4262 receiver->LocalLookup(key, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004263 if (result.IsFound() && result.type() == FIELD) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004264 int offset = result.GetFieldIndex();
4265 keyed_lookup_cache->Update(receiver_map, key, offset);
4266 return receiver->FastPropertyAt(offset);
4267 }
4268 } else {
4269 // Attempt dictionary lookup.
4270 StringDictionary* dictionary = receiver->property_dictionary();
4271 int entry = dictionary->FindEntry(key);
4272 if ((entry != StringDictionary::kNotFound) &&
4273 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4274 Object* value = dictionary->ValueAt(entry);
4275 if (!receiver->IsGlobalObject()) return value;
4276 value = JSGlobalPropertyCell::cast(value)->value();
4277 if (!value->IsTheHole()) return value;
4278 // If value is the hole do the general lookup.
4279 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004280 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004281 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4282 // JSObject without a string key. If the key is a Smi, check for a
4283 // definite out-of-bounds access to elements, which is a strong indicator
4284 // that subsequent accesses will also call the runtime. Proactively
4285 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4286 // doubles for those future calls in the case that the elements would
4287 // become FAST_DOUBLE_ELEMENTS.
4288 Handle<JSObject> js_object(args.at<JSObject>(0));
4289 ElementsKind elements_kind = js_object->GetElementsKind();
4290 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4291 elements_kind == FAST_DOUBLE_ELEMENTS) {
4292 FixedArrayBase* elements = js_object->elements();
4293 if (args.at<Smi>(1)->value() >= elements->length()) {
4294 MaybeObject* maybe_object = TransitionElements(js_object,
4295 FAST_ELEMENTS,
4296 isolate);
4297 if (maybe_object->IsFailure()) return maybe_object;
4298 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004299 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004300 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004301 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4302 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004303 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004304 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004305 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004306 if (index >= 0 && index < str->length()) {
4307 Handle<Object> result = GetCharAt(str, index);
4308 return *result;
4309 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004310 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004311
4312 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004313 return Runtime::GetObjectProperty(isolate,
4314 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004315 args.at<Object>(1));
4316}
4317
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004318// Implements part of 8.12.9 DefineOwnProperty.
4319// There are 3 cases that lead here:
4320// Step 4b - define a new accessor property.
4321// Steps 9c & 12 - replace an existing data property with an accessor property.
4322// Step 12 - update an existing accessor property with an accessor or generic
4323// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004324RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004325 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004326 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004327 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
4328 CONVERT_ARG_CHECKED(String, name, 1);
4329 CONVERT_SMI_ARG_CHECKED(flag_setter, 2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004330 Object* fun = args[3];
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004331 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004332
ager@chromium.org5c838252010-02-19 08:53:10 +00004333 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004334 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004335
4336 RUNTIME_ASSERT(!obj->IsNull());
4337 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004338 return obj->DefineAccessor(name, flag_setter == 0, fun, attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004339}
4340
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004341// Implements part of 8.12.9 DefineOwnProperty.
4342// There are 3 cases that lead here:
4343// Step 4a - define a new data property.
4344// Steps 9b & 12 - replace an existing accessor property with a data property.
4345// Step 12 - update an existing data property with a data or generic
4346// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004347RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004348 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004349 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004350 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
4351 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00004352 Handle<Object> obj_value = args.at<Object>(2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004353 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004354
ager@chromium.org5c838252010-02-19 08:53:10 +00004355 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004356 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4357
4358 // Check if this is an element.
4359 uint32_t index;
4360 bool is_element = name->AsArrayIndex(&index);
4361
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004362 // Special case for elements if any of the flags might be involved.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004363 // If elements are in fast case we always implicitly assume that:
4364 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004365 if (is_element && (attr != NONE ||
4366 js_object->HasLocalElement(index) == JSObject::DICTIONARY_ELEMENT)) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004367 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004368 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004369 // We do not need to do access checks here since these has already
4370 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004371 Handle<Object> proto(js_object->GetPrototype());
4372 // If proxy is detached, ignore the assignment. Alternatively,
4373 // we could throw an exception.
4374 if (proto->IsNull()) return *obj_value;
4375 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004376 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004377
4378 // Don't allow element properties to be redefined on objects with external
4379 // array elements.
4380 if (js_object->HasExternalArrayElements()) {
4381 Handle<Object> args[2] = { js_object, name };
4382 Handle<Object> error =
4383 isolate->factory()->NewTypeError("redef_external_array_element",
4384 HandleVector(args, 2));
4385 return isolate->Throw(*error);
4386 }
4387
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004388 Handle<SeededNumberDictionary> dictionary =
4389 JSObject::NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004390 // Make sure that we never go back to fast case.
4391 dictionary->set_requires_slow_elements();
4392 PropertyDetails details = PropertyDetails(attr, NORMAL);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004393 Handle<SeededNumberDictionary> extended_dictionary =
4394 SeededNumberDictionary::Set(dictionary, index, obj_value, details);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004395 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004396 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004397 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4398 } else {
4399 js_object->set_elements(*extended_dictionary);
4400 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004401 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004402 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004403 }
4404
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004405 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004406 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004407
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004408 // Special case for callback properties.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004409 if (result.IsFound() && result.type() == CALLBACKS) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004410 Object* callback = result.GetCallbackObject();
4411 // To be compatible with Safari we do not change the value on API objects
4412 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4413 // the value.
4414 if (callback->IsAccessorInfo()) {
4415 return isolate->heap()->undefined_value();
4416 }
4417 // Avoid redefining foreign callback as data property, just use the stored
4418 // setter to update the value instead.
4419 // TODO(mstarzinger): So far this only works if property attributes don't
4420 // change, this should be fixed once we cleanup the underlying code.
4421 if (callback->IsForeign() && result.GetAttributes() == attr) {
4422 return js_object->SetPropertyWithCallback(callback,
4423 *name,
4424 *obj_value,
4425 result.holder(),
4426 kStrictMode);
4427 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004428 }
4429
ager@chromium.org5c838252010-02-19 08:53:10 +00004430 // Take special care when attributes are different and there is already
4431 // a property. For simplicity we normalize the property which enables us
4432 // to not worry about changing the instance_descriptor and creating a new
4433 // map. The current version of SetObjectProperty does not handle attributes
4434 // correctly in the case where a property is a field and is reset with
4435 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004436 if (result.IsProperty() &&
4437 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004438 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004439 if (js_object->IsJSGlobalProxy()) {
4440 // Since the result is a property, the prototype will exist so
4441 // we don't have to check for null.
4442 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004443 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004444 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004445 // Use IgnoreAttributes version since a readonly property may be
4446 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004447 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4448 *obj_value,
4449 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004450 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004451
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004452 return Runtime::ForceSetObjectProperty(isolate,
4453 js_object,
4454 name,
4455 obj_value,
4456 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004457}
4458
4459
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004460// Special case for elements if any of the flags are true.
4461// If elements are in fast case we always implicitly assume that:
4462// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4463static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4464 Handle<JSObject> js_object,
4465 uint32_t index,
4466 Handle<Object> value,
4467 PropertyAttributes attr) {
4468 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004469 Handle<SeededNumberDictionary> dictionary =
4470 JSObject::NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004471 // Make sure that we never go back to fast case.
4472 dictionary->set_requires_slow_elements();
4473 PropertyDetails details = PropertyDetails(attr, NORMAL);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004474 Handle<SeededNumberDictionary> extended_dictionary =
4475 SeededNumberDictionary::Set(dictionary, index, value, details);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004476 if (*extended_dictionary != *dictionary) {
4477 js_object->set_elements(*extended_dictionary);
4478 }
4479 return *value;
4480}
4481
4482
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004483MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4484 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004485 Handle<Object> key,
4486 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004487 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004488 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004489 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004490
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004491 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004492 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004493 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004494 isolate->factory()->NewTypeError("non_object_property_store",
4495 HandleVector(args, 2));
4496 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004497 }
4498
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004499 if (object->IsJSProxy()) {
4500 bool has_pending_exception = false;
4501 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4502 if (has_pending_exception) return Failure::Exception();
4503 return JSProxy::cast(*object)->SetProperty(
4504 String::cast(*name), *value, attr, strict_mode);
4505 }
4506
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004507 // If the object isn't a JavaScript object, we ignore the store.
4508 if (!object->IsJSObject()) return *value;
4509
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004510 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4511
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004512 // Check if the given key is an array index.
4513 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004514 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004515 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4516 // of a string using [] notation. We need to support this too in
4517 // JavaScript.
4518 // In the case of a String object we just need to redirect the assignment to
4519 // the underlying string if the index is in range. Since the underlying
4520 // string does nothing with the assignment then we can ignore such
4521 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004522 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004523 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004524 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004525
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004526 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4527 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4528 }
4529
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004530 Handle<Object> result =
4531 JSObject::SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004532 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004533 return *value;
4534 }
4535
4536 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004537 Handle<Object> result;
4538 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004539 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4540 return NormalizeObjectSetElement(isolate,
4541 js_object,
4542 index,
4543 value,
4544 attr);
4545 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004546 result =
4547 JSObject::SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004548 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004549 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004550 key_string->TryFlatten();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004551 result = JSReceiver::SetProperty(
4552 js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004553 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004554 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004555 return *value;
4556 }
4557
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004558 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004559 bool has_pending_exception = false;
4560 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4561 if (has_pending_exception) return Failure::Exception();
4562 Handle<String> name = Handle<String>::cast(converted);
4563
4564 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004565 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004566 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004567 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004568 }
4569}
4570
4571
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004572MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4573 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004574 Handle<Object> key,
4575 Handle<Object> value,
4576 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004577 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004578
4579 // Check if the given key is an array index.
4580 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004581 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004582 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4583 // of a string using [] notation. We need to support this too in
4584 // JavaScript.
4585 // In the case of a String object we just need to redirect the assignment to
4586 // the underlying string if the index is in range. Since the underlying
4587 // string does nothing with the assignment then we can ignore such
4588 // assignments.
4589 if (js_object->IsStringObjectWithCharacterAt(index)) {
4590 return *value;
4591 }
4592
whesse@chromium.org7b260152011-06-20 15:33:18 +00004593 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004594 }
4595
4596 if (key->IsString()) {
4597 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004598 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004599 } else {
4600 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004601 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004602 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4603 *value,
4604 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004605 }
4606 }
4607
4608 // Call-back into JavaScript to convert the key to a string.
4609 bool has_pending_exception = false;
4610 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4611 if (has_pending_exception) return Failure::Exception();
4612 Handle<String> name = Handle<String>::cast(converted);
4613
4614 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004615 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004616 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004617 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004618 }
4619}
4620
4621
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004622MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004623 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004624 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004625 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004626
4627 // Check if the given key is an array index.
4628 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004629 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004630 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4631 // characters of a string using [] notation. In the case of a
4632 // String object we just need to redirect the deletion to the
4633 // underlying string if the index is in range. Since the
4634 // underlying string does nothing with the deletion, we can ignore
4635 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004636 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004637 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004638 }
4639
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004640 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004641 }
4642
4643 Handle<String> key_string;
4644 if (key->IsString()) {
4645 key_string = Handle<String>::cast(key);
4646 } else {
4647 // Call-back into JavaScript to convert the key to a string.
4648 bool has_pending_exception = false;
4649 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4650 if (has_pending_exception) return Failure::Exception();
4651 key_string = Handle<String>::cast(converted);
4652 }
4653
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004654 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004655 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004656}
4657
4658
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004659RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004660 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004661 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004662
4663 Handle<Object> object = args.at<Object>(0);
4664 Handle<Object> key = args.at<Object>(1);
4665 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004666 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004667 RUNTIME_ASSERT(
4668 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004669 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004670 PropertyAttributes attributes =
4671 static_cast<PropertyAttributes>(unchecked_attributes);
4672
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004673 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004674 if (args.length() == 5) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004675 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004676 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004677 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004678
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004679 return Runtime::SetObjectProperty(isolate,
4680 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004681 key,
4682 value,
4683 attributes,
4684 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004685}
4686
4687
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004688RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4689 NoHandleAllocation ha;
4690 RUNTIME_ASSERT(args.length() == 1);
4691 Handle<Object> object = args.at<Object>(0);
4692 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4693}
4694
4695
4696RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4697 NoHandleAllocation ha;
4698 RUNTIME_ASSERT(args.length() == 1);
4699 Handle<Object> object = args.at<Object>(0);
4700 return TransitionElements(object, FAST_ELEMENTS, isolate);
4701}
4702
4703
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004704// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004705// This is used to decide if we should transform null and undefined
4706// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004707RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004708 NoHandleAllocation ha;
4709 RUNTIME_ASSERT(args.length() == 1);
4710
4711 Handle<Object> object = args.at<Object>(0);
4712
4713 if (object->IsJSFunction()) {
4714 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004715 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004716 }
4717 return isolate->heap()->undefined_value();
4718}
4719
4720
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004721RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4722 RUNTIME_ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004723 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004724 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4725 Handle<Object> value = args.at<Object>(2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004726 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004727 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4728 HandleScope scope;
4729
4730 Object* raw_boilerplate_object = literals->get(literal_index);
4731 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4732#if DEBUG
4733 ElementsKind elements_kind = object->GetElementsKind();
4734#endif
4735 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4736 // Smis should never trigger transitions.
4737 ASSERT(!value->IsSmi());
4738
4739 if (value->IsNumber()) {
4740 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004741 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4742 JSObject::TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004743 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4744 FixedDoubleArray* double_array =
4745 FixedDoubleArray::cast(object->elements());
4746 HeapNumber* number = HeapNumber::cast(*value);
4747 double_array->set(store_index, number->Number());
4748 } else {
4749 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4750 elements_kind == FAST_DOUBLE_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004751 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
4752 JSObject::TransitionElementsKind(boilerplate_object, FAST_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004753 FixedArray* object_array =
4754 FixedArray::cast(object->elements());
4755 object_array->set(store_index, *value);
4756 }
4757 return *object;
4758}
4759
4760
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004761// Set a local property, even if it is READ_ONLY. If the property does not
4762// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004763RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004764 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004765 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004766 CONVERT_ARG_CHECKED(JSObject, object, 0);
4767 CONVERT_ARG_CHECKED(String, name, 1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004768 // Compute attributes.
4769 PropertyAttributes attributes = NONE;
4770 if (args.length() == 4) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004771 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004772 // Only attribute bits should be set.
4773 RUNTIME_ASSERT(
4774 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4775 attributes = static_cast<PropertyAttributes>(unchecked_value);
4776 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004777
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004778 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004779 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004780}
4781
4782
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004783RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004784 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004785 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004786
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004787 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4788 CONVERT_ARG_CHECKED(String, key, 1);
4789 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004790 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004791 ? JSReceiver::STRICT_DELETION
4792 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004793}
4794
4795
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004796static Object* HasLocalPropertyImplementation(Isolate* isolate,
4797 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004798 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004799 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004800 // Handle hidden prototypes. If there's a hidden prototype above this thing
4801 // then we have to check it for properties, because they are supposed to
4802 // look like they are on this object.
4803 Handle<Object> proto(object->GetPrototype());
4804 if (proto->IsJSObject() &&
4805 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004806 return HasLocalPropertyImplementation(isolate,
4807 Handle<JSObject>::cast(proto),
4808 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004809 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004810 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004811}
4812
4813
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004814RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004815 NoHandleAllocation ha;
4816 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004817 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004818
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004819 uint32_t index;
4820 const bool key_is_array_index = key->AsArrayIndex(&index);
4821
ager@chromium.org9085a012009-05-11 19:22:57 +00004822 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004823 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004824 if (obj->IsJSObject()) {
4825 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004826 // Fast case: either the key is a real named property or it is not
4827 // an array index and there are no interceptors or hidden
4828 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004829 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004830 Map* map = object->map();
4831 if (!key_is_array_index &&
4832 !map->has_named_interceptor() &&
4833 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4834 return isolate->heap()->false_value();
4835 }
4836 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004837 HandleScope scope(isolate);
4838 return HasLocalPropertyImplementation(isolate,
4839 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004840 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004841 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004842 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004843 String* string = String::cast(obj);
4844 if (index < static_cast<uint32_t>(string->length())) {
4845 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004846 }
4847 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004848 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004849}
4850
4851
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004852RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004853 NoHandleAllocation na;
4854 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004855 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4856 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004857
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004858 bool result = receiver->HasProperty(key);
4859 if (isolate->has_pending_exception()) return Failure::Exception();
4860 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004861}
4862
4863
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004864RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004865 NoHandleAllocation na;
4866 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004867 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4868 CONVERT_SMI_ARG_CHECKED(index, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004869
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004870 bool result = receiver->HasElement(index);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004871 if (isolate->has_pending_exception()) return Failure::Exception();
4872 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004873}
4874
4875
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004876RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004877 NoHandleAllocation ha;
4878 ASSERT(args.length() == 2);
4879
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004880 CONVERT_ARG_CHECKED(JSObject, object, 0);
4881 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004882
4883 uint32_t index;
4884 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004885 JSObject::LocalElementType type = object->HasLocalElement(index);
4886 switch (type) {
4887 case JSObject::UNDEFINED_ELEMENT:
4888 case JSObject::STRING_CHARACTER_ELEMENT:
4889 return isolate->heap()->false_value();
4890 case JSObject::INTERCEPTED_ELEMENT:
4891 case JSObject::FAST_ELEMENT:
4892 return isolate->heap()->true_value();
4893 case JSObject::DICTIONARY_ELEMENT: {
4894 if (object->IsJSGlobalProxy()) {
4895 Object* proto = object->GetPrototype();
4896 if (proto->IsNull()) {
4897 return isolate->heap()->false_value();
4898 }
4899 ASSERT(proto->IsJSGlobalObject());
4900 object = JSObject::cast(proto);
4901 }
4902 FixedArray* elements = FixedArray::cast(object->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004903 SeededNumberDictionary* dictionary = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004904 if (elements->map() ==
4905 isolate->heap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004906 dictionary = SeededNumberDictionary::cast(elements->get(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004907 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004908 dictionary = SeededNumberDictionary::cast(elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004909 }
4910 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004911 ASSERT(entry != SeededNumberDictionary::kNotFound);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004912 PropertyDetails details = dictionary->DetailsAt(entry);
4913 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4914 }
4915 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004916 }
4917
ager@chromium.org870a0b62008-11-04 11:43:05 +00004918 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004919 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004920}
4921
4922
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004923RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004924 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004925 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004926 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004927 bool threw = false;
4928 Handle<JSArray> result = GetKeysFor(object, &threw);
4929 if (threw) return Failure::Exception();
4930 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004931}
4932
4933
4934// Returns either a FixedArray as Runtime_GetPropertyNames,
4935// or, if the given object has an enum cache that contains
4936// all enumerable properties of the object and its prototypes
4937// have none, the map of the object. This is used to speed up
4938// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004939RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004940 ASSERT(args.length() == 1);
4941
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004942 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004943
4944 if (raw_object->IsSimpleEnum()) return raw_object->map();
4945
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004946 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004947 Handle<JSReceiver> object(raw_object);
4948 bool threw = false;
4949 Handle<FixedArray> content =
4950 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4951 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004952
4953 // Test again, since cache may have been built by preceding call.
4954 if (object->IsSimpleEnum()) return object->map();
4955
4956 return *content;
4957}
4958
4959
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004960// Find the length of the prototype chain that is to to handled as one. If a
4961// prototype object is hidden it is to be viewed as part of the the object it
4962// is prototype for.
4963static int LocalPrototypeChainLength(JSObject* obj) {
4964 int count = 1;
4965 Object* proto = obj->GetPrototype();
4966 while (proto->IsJSObject() &&
4967 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4968 count++;
4969 proto = JSObject::cast(proto)->GetPrototype();
4970 }
4971 return count;
4972}
4973
4974
4975// Return the names of the local named properties.
4976// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004977RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004978 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004979 ASSERT(args.length() == 1);
4980 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004981 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004982 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004983 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004984
4985 // Skip the global proxy as it has no properties and always delegates to the
4986 // real global object.
4987 if (obj->IsJSGlobalProxy()) {
4988 // Only collect names if access is permitted.
4989 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004990 !isolate->MayNamedAccess(*obj,
4991 isolate->heap()->undefined_value(),
4992 v8::ACCESS_KEYS)) {
4993 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4994 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004995 }
4996 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4997 }
4998
4999 // Find the number of objects making up this.
5000 int length = LocalPrototypeChainLength(*obj);
5001
5002 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005003 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005004 int total_property_count = 0;
5005 Handle<JSObject> jsproto = obj;
5006 for (int i = 0; i < length; i++) {
5007 // Only collect names if access is permitted.
5008 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005009 !isolate->MayNamedAccess(*jsproto,
5010 isolate->heap()->undefined_value(),
5011 v8::ACCESS_KEYS)) {
5012 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
5013 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005014 }
5015 int n;
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00005016 n = jsproto->NumberOfLocalProperties();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005017 local_property_count[i] = n;
5018 total_property_count += n;
5019 if (i < length - 1) {
5020 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5021 }
5022 }
5023
5024 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005025 Handle<FixedArray> names =
5026 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005027
5028 // Get the property names.
5029 jsproto = obj;
5030 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005031 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005032 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005033 jsproto->GetLocalPropertyNames(*names, next_copy_index);
5034 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00005035 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005036 proto_with_hidden_properties++;
5037 }
5038 if (i < length - 1) {
5039 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5040 }
5041 }
5042
5043 // Filter out name of hidden propeties object.
5044 if (proto_with_hidden_properties > 0) {
5045 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005046 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005047 names->length() - proto_with_hidden_properties);
5048 int dest_pos = 0;
5049 for (int i = 0; i < total_property_count; i++) {
5050 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005051 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005052 continue;
5053 }
5054 names->set(dest_pos++, name);
5055 }
5056 }
5057
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005058 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005059}
5060
5061
5062// Return the names of the local indexed properties.
5063// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005064RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005065 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005066 ASSERT(args.length() == 1);
5067 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005068 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005069 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005070 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005071
5072 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005073 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005074 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005075 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005076}
5077
5078
5079// Return information on whether an object has a named or indexed interceptor.
5080// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005081RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005082 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005083 ASSERT(args.length() == 1);
5084 if (!args[0]->IsJSObject()) {
5085 return Smi::FromInt(0);
5086 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005087 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005088
5089 int result = 0;
5090 if (obj->HasNamedInterceptor()) result |= 2;
5091 if (obj->HasIndexedInterceptor()) result |= 1;
5092
5093 return Smi::FromInt(result);
5094}
5095
5096
5097// Return property names from named interceptor.
5098// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005099RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005100 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005101 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005102 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005103
5104 if (obj->HasNamedInterceptor()) {
5105 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5106 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5107 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005108 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005109}
5110
5111
5112// Return element names from indexed interceptor.
5113// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005114RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005115 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005116 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005117 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005118
5119 if (obj->HasIndexedInterceptor()) {
5120 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5121 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5122 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005123 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005124}
5125
5126
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005127RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005128 ASSERT_EQ(args.length(), 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005129 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005130 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005131 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005132
5133 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005134 // Do access checks before going to the global object.
5135 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005136 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005137 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005138 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5139 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005140 }
5141
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005142 Handle<Object> proto(object->GetPrototype());
5143 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005144 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005145 object = Handle<JSObject>::cast(proto);
5146 }
5147
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005148 bool threw = false;
5149 Handle<FixedArray> contents =
5150 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5151 if (threw) return Failure::Exception();
5152
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005153 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5154 // property array and since the result is mutable we have to create
5155 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005156 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005157 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005158 for (int i = 0; i < length; i++) {
5159 Object* entry = contents->get(i);
5160 if (entry->IsString()) {
5161 copy->set(i, entry);
5162 } else {
5163 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005164 HandleScope scope(isolate);
5165 Handle<Object> entry_handle(entry, isolate);
5166 Handle<Object> entry_str =
5167 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005168 copy->set(i, *entry_str);
5169 }
5170 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005171 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005172}
5173
5174
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005175RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005176 NoHandleAllocation ha;
5177 ASSERT(args.length() == 1);
5178
5179 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005180 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005181 it.AdvanceToArgumentsFrame();
5182 JavaScriptFrame* frame = it.frame();
5183
5184 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005185 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005186
5187 // Try to convert the key to an index. If successful and within
5188 // index return the the argument from the frame.
5189 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005190 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005191 return frame->GetParameter(index);
5192 }
5193
5194 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005195 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005196 bool exception = false;
5197 Handle<Object> converted =
5198 Execution::ToString(args.at<Object>(0), &exception);
5199 if (exception) return Failure::Exception();
5200 Handle<String> key = Handle<String>::cast(converted);
5201
5202 // Try to convert the string key into an array index.
5203 if (key->AsArrayIndex(&index)) {
5204 if (index < n) {
5205 return frame->GetParameter(index);
5206 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005207 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005208 }
5209 }
5210
5211 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005212 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5213 if (key->Equals(isolate->heap()->callee_symbol())) {
5214 Object* function = frame->function();
5215 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005216 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005217 return isolate->Throw(*isolate->factory()->NewTypeError(
5218 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5219 }
5220 return function;
5221 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005222
5223 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005224 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005225}
5226
5227
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005228RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005229 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005230 Object* object = args[0];
5231 return (object->IsJSObject() && !object->IsGlobalObject())
5232 ? JSObject::cast(object)->TransformToFastProperties(0)
5233 : object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005234}
5235
5236
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005237RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005238 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005239 Object* obj = args[0];
5240 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5241 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5242 : obj;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005243}
5244
5245
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005246RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005247 NoHandleAllocation ha;
5248 ASSERT(args.length() == 1);
5249
5250 return args[0]->ToBoolean();
5251}
5252
5253
5254// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5255// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005256RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005257 NoHandleAllocation ha;
5258
5259 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005260 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005261 HeapObject* heap_obj = HeapObject::cast(obj);
5262
5263 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005264 if (heap_obj->map()->is_undetectable()) {
5265 return isolate->heap()->undefined_symbol();
5266 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005267
5268 InstanceType instance_type = heap_obj->map()->instance_type();
5269 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005270 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005271 }
5272
5273 switch (instance_type) {
5274 case ODDBALL_TYPE:
5275 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005276 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005277 }
5278 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005279 return FLAG_harmony_typeof
5280 ? isolate->heap()->null_symbol()
5281 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005282 }
5283 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005284 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005285 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005286 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005287 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005288 default:
5289 // For any kind of object not handled above, the spec rule for
5290 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005291 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005292 }
5293}
5294
5295
lrn@chromium.org25156de2010-04-06 13:10:27 +00005296static bool AreDigits(const char*s, int from, int to) {
5297 for (int i = from; i < to; i++) {
5298 if (s[i] < '0' || s[i] > '9') return false;
5299 }
5300
5301 return true;
5302}
5303
5304
5305static int ParseDecimalInteger(const char*s, int from, int to) {
5306 ASSERT(to - from < 10); // Overflow is not possible.
5307 ASSERT(from < to);
5308 int d = s[from] - '0';
5309
5310 for (int i = from + 1; i < to; i++) {
5311 d = 10 * d + (s[i] - '0');
5312 }
5313
5314 return d;
5315}
5316
5317
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005318RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005319 NoHandleAllocation ha;
5320 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005321 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005322 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005323
5324 // Fast case: short integer or some sorts of junk values.
5325 int len = subject->length();
5326 if (subject->IsSeqAsciiString()) {
5327 if (len == 0) return Smi::FromInt(0);
5328
5329 char const* data = SeqAsciiString::cast(subject)->GetChars();
5330 bool minus = (data[0] == '-');
5331 int start_pos = (minus ? 1 : 0);
5332
5333 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005334 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005335 } else if (data[start_pos] > '9') {
5336 // Fast check for a junk value. A valid string may start from a
5337 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5338 // the 'I' character ('Infinity'). All of that have codes not greater than
5339 // '9' except 'I'.
5340 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005341 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005342 }
5343 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5344 // The maximal/minimal smi has 10 digits. If the string has less digits we
5345 // know it will fit into the smi-data type.
5346 int d = ParseDecimalInteger(data, start_pos, len);
5347 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005348 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005349 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005350 } else if (!subject->HasHashCode() &&
5351 len <= String::kMaxArrayIndexSize &&
5352 (len == 1 || data[0] != '0')) {
5353 // String hash is not calculated yet but all the data are present.
5354 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005355 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005356#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005357 subject->Hash(); // Force hash calculation.
5358 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5359 static_cast<int>(hash));
5360#endif
5361 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005362 }
5363 return Smi::FromInt(d);
5364 }
5365 }
5366
5367 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005368 return isolate->heap()->NumberFromDouble(
5369 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005370}
5371
5372
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005373RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005374 NoHandleAllocation ha;
5375 ASSERT(args.length() == 1);
5376
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005377 CONVERT_ARG_CHECKED(JSArray, codes, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005378 int length = Smi::cast(codes->length())->value();
5379
5380 // Check if the string can be ASCII.
5381 int i;
5382 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005383 Object* element;
5384 { MaybeObject* maybe_element = codes->GetElement(i);
5385 // We probably can't get an exception here, but just in order to enforce
5386 // the checking of inputs in the runtime calls we check here.
5387 if (!maybe_element->ToObject(&element)) return maybe_element;
5388 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005389 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5390 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5391 break;
5392 }
5393
lrn@chromium.org303ada72010-10-27 09:33:13 +00005394 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005395 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005396 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005397 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005398 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005399 }
5400
lrn@chromium.org303ada72010-10-27 09:33:13 +00005401 Object* object = NULL;
5402 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005403 String* result = String::cast(object);
5404 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005405 Object* element;
5406 { MaybeObject* maybe_element = codes->GetElement(i);
5407 if (!maybe_element->ToObject(&element)) return maybe_element;
5408 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005409 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005410 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005411 }
5412 return result;
5413}
5414
5415
5416// kNotEscaped is generated by the following:
5417//
5418// #!/bin/perl
5419// for (my $i = 0; $i < 256; $i++) {
5420// print "\n" if $i % 16 == 0;
5421// my $c = chr($i);
5422// my $escaped = 1;
5423// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5424// print $escaped ? "0, " : "1, ";
5425// }
5426
5427
5428static bool IsNotEscaped(uint16_t character) {
5429 // Only for 8 bit characters, the rest are always escaped (in a different way)
5430 ASSERT(character < 256);
5431 static const char kNotEscaped[256] = {
5432 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5433 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5434 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5435 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5436 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5437 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5438 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5439 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5440 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5441 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5442 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5443 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5444 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5445 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5446 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5447 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5448 };
5449 return kNotEscaped[character] != 0;
5450}
5451
5452
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005453RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005454 const char hex_chars[] = "0123456789ABCDEF";
5455 NoHandleAllocation ha;
5456 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005457 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005458
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005459 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005460
5461 int escaped_length = 0;
5462 int length = source->length();
5463 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005464 Access<StringInputBuffer> buffer(
5465 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005466 buffer->Reset(source);
5467 while (buffer->has_more()) {
5468 uint16_t character = buffer->GetNext();
5469 if (character >= 256) {
5470 escaped_length += 6;
5471 } else if (IsNotEscaped(character)) {
5472 escaped_length++;
5473 } else {
5474 escaped_length += 3;
5475 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005476 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005477 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005478 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005479 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005480 return Failure::OutOfMemoryException();
5481 }
5482 }
5483 }
5484 // No length change implies no change. Return original string if no change.
5485 if (escaped_length == length) {
5486 return source;
5487 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005488 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005489 { MaybeObject* maybe_o =
5490 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005491 if (!maybe_o->ToObject(&o)) return maybe_o;
5492 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005493 String* destination = String::cast(o);
5494 int dest_position = 0;
5495
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005496 Access<StringInputBuffer> buffer(
5497 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005498 buffer->Rewind();
5499 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005500 uint16_t chr = buffer->GetNext();
5501 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005502 destination->Set(dest_position, '%');
5503 destination->Set(dest_position+1, 'u');
5504 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5505 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5506 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5507 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005508 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005509 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005510 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005511 dest_position++;
5512 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005513 destination->Set(dest_position, '%');
5514 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5515 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005516 dest_position += 3;
5517 }
5518 }
5519 return destination;
5520}
5521
5522
5523static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5524 static const signed char kHexValue['g'] = {
5525 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5526 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5527 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5528 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5529 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5530 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5531 -1, 10, 11, 12, 13, 14, 15 };
5532
5533 if (character1 > 'f') return -1;
5534 int hi = kHexValue[character1];
5535 if (hi == -1) return -1;
5536 if (character2 > 'f') return -1;
5537 int lo = kHexValue[character2];
5538 if (lo == -1) return -1;
5539 return (hi << 4) + lo;
5540}
5541
5542
ager@chromium.org870a0b62008-11-04 11:43:05 +00005543static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005544 int i,
5545 int length,
5546 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005547 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005548 int32_t hi = 0;
5549 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005550 if (character == '%' &&
5551 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005552 source->Get(i + 1) == 'u' &&
5553 (hi = TwoDigitHex(source->Get(i + 2),
5554 source->Get(i + 3))) != -1 &&
5555 (lo = TwoDigitHex(source->Get(i + 4),
5556 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005557 *step = 6;
5558 return (hi << 8) + lo;
5559 } else if (character == '%' &&
5560 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005561 (lo = TwoDigitHex(source->Get(i + 1),
5562 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005563 *step = 3;
5564 return lo;
5565 } else {
5566 *step = 1;
5567 return character;
5568 }
5569}
5570
5571
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005572RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005573 NoHandleAllocation ha;
5574 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005575 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005576
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005577 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005578
5579 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005580 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005581
5582 int unescaped_length = 0;
5583 for (int i = 0; i < length; unescaped_length++) {
5584 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005585 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005586 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005587 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005588 i += step;
5589 }
5590
5591 // No length change implies no change. Return original string if no change.
5592 if (unescaped_length == length)
5593 return source;
5594
lrn@chromium.org303ada72010-10-27 09:33:13 +00005595 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005596 { MaybeObject* maybe_o =
5597 ascii ?
5598 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5599 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005600 if (!maybe_o->ToObject(&o)) return maybe_o;
5601 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005602 String* destination = String::cast(o);
5603
5604 int dest_position = 0;
5605 for (int i = 0; i < length; dest_position++) {
5606 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005607 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005608 i += step;
5609 }
5610 return destination;
5611}
5612
5613
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005614static const unsigned int kQuoteTableLength = 128u;
5615
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005616static const int kJsonQuotesCharactersPerEntry = 8;
5617static const char* const JsonQuotes =
5618 "\\u0000 \\u0001 \\u0002 \\u0003 "
5619 "\\u0004 \\u0005 \\u0006 \\u0007 "
5620 "\\b \\t \\n \\u000b "
5621 "\\f \\r \\u000e \\u000f "
5622 "\\u0010 \\u0011 \\u0012 \\u0013 "
5623 "\\u0014 \\u0015 \\u0016 \\u0017 "
5624 "\\u0018 \\u0019 \\u001a \\u001b "
5625 "\\u001c \\u001d \\u001e \\u001f "
5626 " ! \\\" # "
5627 "$ % & ' "
5628 "( ) * + "
5629 ", - . / "
5630 "0 1 2 3 "
5631 "4 5 6 7 "
5632 "8 9 : ; "
5633 "< = > ? "
5634 "@ A B C "
5635 "D E F G "
5636 "H I J K "
5637 "L M N O "
5638 "P Q R S "
5639 "T U V W "
5640 "X Y Z [ "
5641 "\\\\ ] ^ _ "
5642 "` a b c "
5643 "d e f g "
5644 "h i j k "
5645 "l m n o "
5646 "p q r s "
5647 "t u v w "
5648 "x y z { "
5649 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005650
5651
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005652// For a string that is less than 32k characters it should always be
5653// possible to allocate it in new space.
5654static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5655
5656
5657// Doing JSON quoting cannot make the string more than this many times larger.
5658static const int kJsonQuoteWorstCaseBlowup = 6;
5659
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005660static const int kSpaceForQuotesAndComma = 3;
5661static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005662
5663// Covers the entire ASCII range (all other characters are unchanged by JSON
5664// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005665static const byte JsonQuoteLengths[kQuoteTableLength] = {
5666 6, 6, 6, 6, 6, 6, 6, 6,
5667 2, 2, 2, 6, 2, 2, 6, 6,
5668 6, 6, 6, 6, 6, 6, 6, 6,
5669 6, 6, 6, 6, 6, 6, 6, 6,
5670 1, 1, 2, 1, 1, 1, 1, 1,
5671 1, 1, 1, 1, 1, 1, 1, 1,
5672 1, 1, 1, 1, 1, 1, 1, 1,
5673 1, 1, 1, 1, 1, 1, 1, 1,
5674 1, 1, 1, 1, 1, 1, 1, 1,
5675 1, 1, 1, 1, 1, 1, 1, 1,
5676 1, 1, 1, 1, 1, 1, 1, 1,
5677 1, 1, 1, 1, 2, 1, 1, 1,
5678 1, 1, 1, 1, 1, 1, 1, 1,
5679 1, 1, 1, 1, 1, 1, 1, 1,
5680 1, 1, 1, 1, 1, 1, 1, 1,
5681 1, 1, 1, 1, 1, 1, 1, 1,
5682};
5683
5684
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005685template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005686MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005687
5688
5689template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005690MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5691 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005692}
5693
5694
5695template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005696MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5697 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005698}
5699
5700
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005701template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005702static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5703 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005704 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005705 const Char* read_cursor = characters.start();
5706 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005707 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005708 int quoted_length = kSpaceForQuotes;
5709 while (read_cursor < end) {
5710 Char c = *(read_cursor++);
5711 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5712 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005713 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005714 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005715 }
5716 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005717 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5718 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005719 Object* new_object;
5720 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005721 return new_alloc;
5722 }
5723 StringType* new_string = StringType::cast(new_object);
5724
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005725 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005726 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005727 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005728 *(write_cursor++) = '"';
5729
5730 read_cursor = characters.start();
5731 while (read_cursor < end) {
5732 Char c = *(read_cursor++);
5733 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5734 *(write_cursor++) = c;
5735 } else {
5736 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5737 const char* replacement = JsonQuotes +
5738 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5739 for (int i = 0; i < len; i++) {
5740 *write_cursor++ = *replacement++;
5741 }
5742 }
5743 }
5744 *(write_cursor++) = '"';
5745 return new_string;
5746}
5747
5748
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005749template <typename SinkChar, typename SourceChar>
5750static inline SinkChar* WriteQuoteJsonString(
5751 Isolate* isolate,
5752 SinkChar* write_cursor,
5753 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005754 // SinkChar is only char if SourceChar is guaranteed to be char.
5755 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005756 const SourceChar* read_cursor = characters.start();
5757 const SourceChar* end = read_cursor + characters.length();
5758 *(write_cursor++) = '"';
5759 while (read_cursor < end) {
5760 SourceChar c = *(read_cursor++);
5761 if (sizeof(SourceChar) > 1u &&
5762 static_cast<unsigned>(c) >= kQuoteTableLength) {
5763 *(write_cursor++) = static_cast<SinkChar>(c);
5764 } else {
5765 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5766 const char* replacement = JsonQuotes +
5767 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5768 write_cursor[0] = replacement[0];
5769 if (len > 1) {
5770 write_cursor[1] = replacement[1];
5771 if (len > 2) {
5772 ASSERT(len == 6);
5773 write_cursor[2] = replacement[2];
5774 write_cursor[3] = replacement[3];
5775 write_cursor[4] = replacement[4];
5776 write_cursor[5] = replacement[5];
5777 }
5778 }
5779 write_cursor += len;
5780 }
5781 }
5782 *(write_cursor++) = '"';
5783 return write_cursor;
5784}
5785
5786
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005787template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005788static MaybeObject* QuoteJsonString(Isolate* isolate,
5789 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005790 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005791 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005792 int worst_case_length =
5793 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005794 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005795 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005796 }
5797
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005798 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5799 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005800 Object* new_object;
5801 if (!new_alloc->ToObject(&new_object)) {
5802 return new_alloc;
5803 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005804 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005805 // Even if our string is small enough to fit in new space we still have to
5806 // handle it being allocated in old space as may happen in the third
5807 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5808 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005809 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005810 }
5811 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005812 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005813
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005814 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005815 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005816 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005817 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5818 write_cursor,
5819 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005820 int final_length = static_cast<int>(
5821 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005822 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005823 isolate->heap()->new_space()->
5824 template ShrinkStringAtAllocationBoundary<StringType>(
5825 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005826 return new_string;
5827}
5828
5829
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005830RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005831 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005832 CONVERT_ARG_CHECKED(String, str, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005833 if (!str->IsFlat()) {
5834 MaybeObject* try_flatten = str->TryFlatten();
5835 Object* flat;
5836 if (!try_flatten->ToObject(&flat)) {
5837 return try_flatten;
5838 }
5839 str = String::cast(flat);
5840 ASSERT(str->IsFlat());
5841 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005842 String::FlatContent flat = str->GetFlatContent();
5843 ASSERT(flat.IsFlat());
5844 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005845 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005846 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005847 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005848 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005849 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005850 }
5851}
5852
5853
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005854RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005855 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005856 CONVERT_ARG_CHECKED(String, str, 0);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005857 if (!str->IsFlat()) {
5858 MaybeObject* try_flatten = str->TryFlatten();
5859 Object* flat;
5860 if (!try_flatten->ToObject(&flat)) {
5861 return try_flatten;
5862 }
5863 str = String::cast(flat);
5864 ASSERT(str->IsFlat());
5865 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005866 String::FlatContent flat = str->GetFlatContent();
5867 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005868 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005869 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005870 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005871 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005872 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005873 }
5874}
5875
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005876
5877template <typename Char, typename StringType>
5878static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5879 FixedArray* array,
5880 int worst_case_length) {
5881 int length = array->length();
5882
5883 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5884 worst_case_length);
5885 Object* new_object;
5886 if (!new_alloc->ToObject(&new_object)) {
5887 return new_alloc;
5888 }
5889 if (!isolate->heap()->new_space()->Contains(new_object)) {
5890 // Even if our string is small enough to fit in new space we still have to
5891 // handle it being allocated in old space as may happen in the third
5892 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5893 // CEntryStub::GenerateCore.
5894 return isolate->heap()->undefined_value();
5895 }
5896 AssertNoAllocation no_gc;
5897 StringType* new_string = StringType::cast(new_object);
5898 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5899
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005900 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005901 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005902 *(write_cursor++) = '[';
5903 for (int i = 0; i < length; i++) {
5904 if (i != 0) *(write_cursor++) = ',';
5905 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005906 String::FlatContent content = str->GetFlatContent();
5907 ASSERT(content.IsFlat());
5908 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005909 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5910 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005911 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005912 } else {
5913 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5914 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005915 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005916 }
5917 }
5918 *(write_cursor++) = ']';
5919
5920 int final_length = static_cast<int>(
5921 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005922 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005923 isolate->heap()->new_space()->
5924 template ShrinkStringAtAllocationBoundary<StringType>(
5925 new_string, final_length);
5926 return new_string;
5927}
5928
5929
5930RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5931 NoHandleAllocation ha;
5932 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005933 CONVERT_ARG_CHECKED(JSArray, array, 0);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005934
5935 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5936 FixedArray* elements = FixedArray::cast(array->elements());
5937 int n = elements->length();
5938 bool ascii = true;
5939 int total_length = 0;
5940
5941 for (int i = 0; i < n; i++) {
5942 Object* elt = elements->get(i);
5943 if (!elt->IsString()) return isolate->heap()->undefined_value();
5944 String* element = String::cast(elt);
5945 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5946 total_length += element->length();
5947 if (ascii && element->IsTwoByteRepresentation()) {
5948 ascii = false;
5949 }
5950 }
5951
5952 int worst_case_length =
5953 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5954 + total_length * kJsonQuoteWorstCaseBlowup;
5955
5956 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5957 return isolate->heap()->undefined_value();
5958 }
5959
5960 if (ascii) {
5961 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5962 elements,
5963 worst_case_length);
5964 } else {
5965 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5966 elements,
5967 worst_case_length);
5968 }
5969}
5970
5971
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005972RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005973 NoHandleAllocation ha;
5974
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005975 CONVERT_ARG_CHECKED(String, s, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005976 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005977
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005978 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005979
lrn@chromium.org25156de2010-04-06 13:10:27 +00005980 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005981 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005982 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005983}
5984
5985
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005986RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005987 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005988 CONVERT_ARG_CHECKED(String, str, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005989
5990 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005991 double value = StringToDouble(isolate->unicode_cache(),
5992 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005993
5994 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005995 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005996}
5997
5998
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005999template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006000MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006001 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00006002 String* s,
6003 int length,
6004 int input_string_length,
6005 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006006 // We try this twice, once with the assumption that the result is no longer
6007 // than the input and, if that assumption breaks, again with the exact
6008 // length. This may not be pretty, but it is nicer than what was here before
6009 // and I hereby claim my vaffel-is.
6010 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006011 // Allocate the resulting string.
6012 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006013 // NOTE: This assumes that the upper/lower case of an ASCII
6014 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006015 // might break in the future if we implement more context and locale
6016 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006017 Object* o;
6018 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006019 ? isolate->heap()->AllocateRawAsciiString(length)
6020 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006021 if (!maybe_o->ToObject(&o)) return maybe_o;
6022 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006023 String* result = String::cast(o);
6024 bool has_changed_character = false;
6025
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006026 // Convert all characters to upper case, assuming that they will fit
6027 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006028 Access<StringInputBuffer> buffer(
6029 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006030 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006031 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006032 // We can assume that the string is not empty
6033 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006034 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006035 bool has_next = buffer->has_more();
6036 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006037 int char_length = mapping->get(current, next, chars);
6038 if (char_length == 0) {
6039 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006040 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006041 i++;
6042 } else if (char_length == 1) {
6043 // Common case: converting the letter resulted in one character.
6044 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006045 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006046 has_changed_character = true;
6047 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006048 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006049 // We've assumed that the result would be as long as the
6050 // input but here is a character that converts to several
6051 // characters. No matter, we calculate the exact length
6052 // of the result and try the whole thing again.
6053 //
6054 // Note that this leaves room for optimization. We could just
6055 // memcpy what we already have to the result string. Also,
6056 // the result string is the last object allocated we could
6057 // "realloc" it and probably, in the vast majority of cases,
6058 // extend the existing string to be able to hold the full
6059 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006060 int next_length = 0;
6061 if (has_next) {
6062 next_length = mapping->get(next, 0, chars);
6063 if (next_length == 0) next_length = 1;
6064 }
6065 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006066 while (buffer->has_more()) {
6067 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006068 // NOTE: we use 0 as the next character here because, while
6069 // the next character may affect what a character converts to,
6070 // it does not in any case affect the length of what it convert
6071 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006072 int char_length = mapping->get(current, 0, chars);
6073 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006074 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006075 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006076 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006077 return Failure::OutOfMemoryException();
6078 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006079 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006080 // Try again with the real length.
6081 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006082 } else {
6083 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006084 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006085 i++;
6086 }
6087 has_changed_character = true;
6088 }
6089 current = next;
6090 }
6091 if (has_changed_character) {
6092 return result;
6093 } else {
6094 // If we didn't actually change anything in doing the conversion
6095 // we simple return the result and let the converted string
6096 // become garbage; there is no reason to keep two identical strings
6097 // alive.
6098 return s;
6099 }
6100}
6101
6102
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006103namespace {
6104
lrn@chromium.org303ada72010-10-27 09:33:13 +00006105static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6106
6107
6108// Given a word and two range boundaries returns a word with high bit
6109// set in every byte iff the corresponding input byte was strictly in
6110// the range (m, n). All the other bits in the result are cleared.
6111// This function is only useful when it can be inlined and the
6112// boundaries are statically known.
6113// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006114// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006115static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006116 // Every byte in an ASCII string is less than or equal to 0x7F.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006117 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6118 // Use strict inequalities since in edge cases the function could be
6119 // further simplified.
6120 ASSERT(0 < m && m < n && n < 0x7F);
6121 // Has high bit set in every w byte less than n.
6122 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6123 // Has high bit set in every w byte greater than m.
6124 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6125 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6126}
6127
6128
6129enum AsciiCaseConversion {
6130 ASCII_TO_LOWER,
6131 ASCII_TO_UPPER
6132};
6133
6134
6135template <AsciiCaseConversion dir>
6136struct FastAsciiConverter {
6137 static bool Convert(char* dst, char* src, int length) {
6138#ifdef DEBUG
6139 char* saved_dst = dst;
6140 char* saved_src = src;
6141#endif
6142 // We rely on the distance between upper and lower case letters
6143 // being a known power of 2.
6144 ASSERT('a' - 'A' == (1 << 5));
6145 // Boundaries for the range of input characters than require conversion.
6146 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6147 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6148 bool changed = false;
6149 char* const limit = src + length;
6150#ifdef V8_HOST_CAN_READ_UNALIGNED
6151 // Process the prefix of the input that requires no conversion one
6152 // (machine) word at a time.
6153 while (src <= limit - sizeof(uintptr_t)) {
6154 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6155 if (AsciiRangeMask(w, lo, hi) != 0) {
6156 changed = true;
6157 break;
6158 }
6159 *reinterpret_cast<uintptr_t*>(dst) = w;
6160 src += sizeof(uintptr_t);
6161 dst += sizeof(uintptr_t);
6162 }
6163 // Process the remainder of the input performing conversion when
6164 // required one word at a time.
6165 while (src <= limit - sizeof(uintptr_t)) {
6166 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6167 uintptr_t m = AsciiRangeMask(w, lo, hi);
6168 // The mask has high (7th) bit set in every byte that needs
6169 // conversion and we know that the distance between cases is
6170 // 1 << 5.
6171 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6172 src += sizeof(uintptr_t);
6173 dst += sizeof(uintptr_t);
6174 }
6175#endif
6176 // Process the last few bytes of the input (or the whole input if
6177 // unaligned access is not supported).
6178 while (src < limit) {
6179 char c = *src;
6180 if (lo < c && c < hi) {
6181 c ^= (1 << 5);
6182 changed = true;
6183 }
6184 *dst = c;
6185 ++src;
6186 ++dst;
6187 }
6188#ifdef DEBUG
6189 CheckConvert(saved_dst, saved_src, length, changed);
6190#endif
6191 return changed;
6192 }
6193
6194#ifdef DEBUG
6195 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6196 bool expected_changed = false;
6197 for (int i = 0; i < length; i++) {
6198 if (dst[i] == src[i]) continue;
6199 expected_changed = true;
6200 if (dir == ASCII_TO_LOWER) {
6201 ASSERT('A' <= src[i] && src[i] <= 'Z');
6202 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6203 } else {
6204 ASSERT(dir == ASCII_TO_UPPER);
6205 ASSERT('a' <= src[i] && src[i] <= 'z');
6206 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6207 }
6208 }
6209 ASSERT(expected_changed == changed);
6210 }
6211#endif
6212};
6213
6214
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006215struct ToLowerTraits {
6216 typedef unibrow::ToLowercase UnibrowConverter;
6217
lrn@chromium.org303ada72010-10-27 09:33:13 +00006218 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006219};
6220
6221
6222struct ToUpperTraits {
6223 typedef unibrow::ToUppercase UnibrowConverter;
6224
lrn@chromium.org303ada72010-10-27 09:33:13 +00006225 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006226};
6227
6228} // namespace
6229
6230
6231template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006232MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006233 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006234 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006235 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006236 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006237 CONVERT_ARG_CHECKED(String, s, 0);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006238 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006239
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006240 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006241 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006242 if (length == 0) return s;
6243
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006244 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006245 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006246 // NOTE: This assumes that the upper/lower case of an ASCII
6247 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006248 // might break in the future if we implement more context and locale
6249 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006250 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006251 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006252 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006253 if (!maybe_o->ToObject(&o)) return maybe_o;
6254 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006255 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006256 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006257 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006258 return has_changed_character ? result : s;
6259 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006260
lrn@chromium.org303ada72010-10-27 09:33:13 +00006261 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006262 { MaybeObject* maybe_answer =
6263 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006264 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6265 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006266 if (answer->IsSmi()) {
6267 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006268 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006269 ConvertCaseHelper(isolate,
6270 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006271 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6272 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006273 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006274 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006275}
6276
6277
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006278RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006279 return ConvertCase<ToLowerTraits>(
6280 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006281}
6282
6283
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006284RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006285 return ConvertCase<ToUpperTraits>(
6286 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006287}
6288
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006289
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006290static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006291 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006292}
6293
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006294
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006295RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006296 NoHandleAllocation ha;
6297 ASSERT(args.length() == 3);
6298
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006299 CONVERT_ARG_CHECKED(String, s, 0);
6300 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6301 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006302
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006303 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006304 int length = s->length();
6305
6306 int left = 0;
6307 if (trimLeft) {
6308 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6309 left++;
6310 }
6311 }
6312
6313 int right = length;
6314 if (trimRight) {
6315 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6316 right--;
6317 }
6318 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006319 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006320}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006321
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006322
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006323RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006324 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006325 HandleScope handle_scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006326 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6327 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006328 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6329
6330 int subject_length = subject->length();
6331 int pattern_length = pattern->length();
6332 RUNTIME_ASSERT(pattern_length > 0);
6333
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006334 if (limit == 0xffffffffu) {
6335 Handle<Object> cached_answer(StringSplitCache::Lookup(
6336 isolate->heap()->string_split_cache(),
6337 *subject,
6338 *pattern));
6339 if (*cached_answer != Smi::FromInt(0)) {
6340 Handle<JSArray> result =
6341 isolate->factory()->NewJSArrayWithElements(
6342 Handle<FixedArray>::cast(cached_answer));
6343 return *result;
6344 }
6345 }
6346
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006347 // The limit can be very large (0xffffffffu), but since the pattern
6348 // isn't empty, we can never create more parts than ~half the length
6349 // of the subject.
6350
6351 if (!subject->IsFlat()) FlattenString(subject);
6352
6353 static const int kMaxInitialListCapacity = 16;
6354
danno@chromium.org40cb8782011-05-25 07:58:50 +00006355 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006356
6357 // Find (up to limit) indices of separator and end-of-string in subject
6358 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6359 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006360 if (!pattern->IsFlat()) FlattenString(pattern);
6361
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006362 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006363
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006364 if (static_cast<uint32_t>(indices.length()) < limit) {
6365 indices.Add(subject_length);
6366 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006367
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006368 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006369
6370 // Create JSArray of substrings separated by separator.
6371 int part_count = indices.length();
6372
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006373 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006374 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006375 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006376 result->set_length(Smi::FromInt(part_count));
6377
6378 ASSERT(result->HasFastElements());
6379
6380 if (part_count == 1 && indices.at(0) == subject_length) {
6381 FixedArray::cast(result->elements())->set(0, *subject);
6382 return *result;
6383 }
6384
6385 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6386 int part_start = 0;
6387 for (int i = 0; i < part_count; i++) {
6388 HandleScope local_loop_handle;
6389 int part_end = indices.at(i);
6390 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006391 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006392 elements->set(i, *substring);
6393 part_start = part_end + pattern_length;
6394 }
6395
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006396 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006397 if (result->HasFastElements()) {
6398 StringSplitCache::Enter(isolate->heap(),
6399 isolate->heap()->string_split_cache(),
6400 *subject,
6401 *pattern,
6402 *elements);
6403 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006404 }
6405
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006406 return *result;
6407}
6408
6409
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006410// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006411// one-char strings in the cache. Gives up on the first char that is
6412// not in the cache and fills the remainder with smi zeros. Returns
6413// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006414static int CopyCachedAsciiCharsToArray(Heap* heap,
6415 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006416 FixedArray* elements,
6417 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006418 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006419 FixedArray* ascii_cache = heap->single_character_string_cache();
6420 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006421 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006422 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006423 for (i = 0; i < length; ++i) {
6424 Object* value = ascii_cache->get(chars[i]);
6425 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006426 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006427 }
6428 if (i < length) {
6429 ASSERT(Smi::FromInt(0) == 0);
6430 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6431 }
6432#ifdef DEBUG
6433 for (int j = 0; j < length; ++j) {
6434 Object* element = elements->get(j);
6435 ASSERT(element == Smi::FromInt(0) ||
6436 (element->IsString() && String::cast(element)->LooksValid()));
6437 }
6438#endif
6439 return i;
6440}
6441
6442
6443// Converts a String to JSArray.
6444// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006445RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006446 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006447 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006448 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006449 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006450
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006451 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006452 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006453
6454 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006455 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006456 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006457 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006458 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006459 { MaybeObject* maybe_obj =
6460 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006461 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6462 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006463 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006464 String::FlatContent content = s->GetFlatContent();
6465 if (content.IsAscii()) {
6466 Vector<const char> chars = content.ToAsciiVector();
6467 // Note, this will initialize all elements (not only the prefix)
6468 // to prevent GC from seeing partially initialized array.
6469 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6470 chars.start(),
6471 *elements,
6472 length);
6473 } else {
6474 MemsetPointer(elements->data_start(),
6475 isolate->heap()->undefined_value(),
6476 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006477 }
6478 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006479 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006480 }
6481 for (int i = position; i < length; ++i) {
6482 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6483 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006484 }
6485
6486#ifdef DEBUG
6487 for (int i = 0; i < length; ++i) {
6488 ASSERT(String::cast(elements->get(i))->length() == 1);
6489 }
6490#endif
6491
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006492 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006493}
6494
6495
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006496RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006497 NoHandleAllocation ha;
6498 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006499 CONVERT_ARG_CHECKED(String, value, 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006500 return value->ToObject();
6501}
6502
6503
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006504bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006505 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006506 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006507 return char_length == 0;
6508}
6509
6510
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006511RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006512 NoHandleAllocation ha;
6513 ASSERT(args.length() == 1);
6514
6515 Object* number = args[0];
6516 RUNTIME_ASSERT(number->IsNumber());
6517
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006518 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006519}
6520
6521
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006522RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006523 NoHandleAllocation ha;
6524 ASSERT(args.length() == 1);
6525
6526 Object* number = args[0];
6527 RUNTIME_ASSERT(number->IsNumber());
6528
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006529 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006530}
6531
6532
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006533RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006534 NoHandleAllocation ha;
6535 ASSERT(args.length() == 1);
6536
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006537 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006538
6539 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6540 if (number > 0 && number <= Smi::kMaxValue) {
6541 return Smi::FromInt(static_cast<int>(number));
6542 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006543 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006544}
6545
6546
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006547RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006548 NoHandleAllocation ha;
6549 ASSERT(args.length() == 1);
6550
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006551 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006552
6553 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6554 if (number > 0 && number <= Smi::kMaxValue) {
6555 return Smi::FromInt(static_cast<int>(number));
6556 }
6557
6558 double double_value = DoubleToInteger(number);
6559 // Map both -0 and +0 to +0.
6560 if (double_value == 0) double_value = 0;
6561
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006562 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006563}
6564
6565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006566RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006567 NoHandleAllocation ha;
6568 ASSERT(args.length() == 1);
6569
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006570 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006571 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006572}
6573
6574
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006575RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006576 NoHandleAllocation ha;
6577 ASSERT(args.length() == 1);
6578
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006579 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006580
6581 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6582 if (number > 0 && number <= Smi::kMaxValue) {
6583 return Smi::FromInt(static_cast<int>(number));
6584 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006585 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006586}
6587
6588
ager@chromium.org870a0b62008-11-04 11:43:05 +00006589// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6590// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006591RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006592 NoHandleAllocation ha;
6593 ASSERT(args.length() == 1);
6594
6595 Object* obj = args[0];
6596 if (obj->IsSmi()) {
6597 return obj;
6598 }
6599 if (obj->IsHeapNumber()) {
6600 double value = HeapNumber::cast(obj)->value();
6601 int int_value = FastD2I(value);
6602 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6603 return Smi::FromInt(int_value);
6604 }
6605 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006606 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006607}
6608
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006609
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006610RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006611 NoHandleAllocation ha;
6612 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006613 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006614}
6615
6616
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006617RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006618 NoHandleAllocation ha;
6619 ASSERT(args.length() == 2);
6620
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006621 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6622 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006623 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006624}
6625
6626
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006627RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006628 NoHandleAllocation ha;
6629 ASSERT(args.length() == 2);
6630
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006631 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6632 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006633 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006634}
6635
6636
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006637RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006638 NoHandleAllocation ha;
6639 ASSERT(args.length() == 2);
6640
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006641 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6642 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006643 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006644}
6645
6646
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006647RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006648 NoHandleAllocation ha;
6649 ASSERT(args.length() == 1);
6650
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006651 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006652 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006653}
6654
6655
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006656RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006657 NoHandleAllocation ha;
6658 ASSERT(args.length() == 0);
6659
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006660 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006661}
6662
6663
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006664RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006665 NoHandleAllocation ha;
6666 ASSERT(args.length() == 2);
6667
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006668 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6669 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006670 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006671}
6672
6673
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006674RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006675 NoHandleAllocation ha;
6676 ASSERT(args.length() == 2);
6677
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006678 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6679 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006680
ager@chromium.org3811b432009-10-28 14:53:37 +00006681 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006682 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006683 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006684}
6685
6686
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006687RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006688 NoHandleAllocation ha;
6689 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006690 CONVERT_ARG_CHECKED(String, str1, 0);
6691 CONVERT_ARG_CHECKED(String, str2, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006692 isolate->counters()->string_add_runtime()->Increment();
6693 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006694}
6695
6696
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006697template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006698static inline void StringBuilderConcatHelper(String* special,
6699 sinkchar* sink,
6700 FixedArray* fixed_array,
6701 int array_length) {
6702 int position = 0;
6703 for (int i = 0; i < array_length; i++) {
6704 Object* element = fixed_array->get(i);
6705 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006706 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006707 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006708 int pos;
6709 int len;
6710 if (encoded_slice > 0) {
6711 // Position and length encoded in one smi.
6712 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6713 len = StringBuilderSubstringLength::decode(encoded_slice);
6714 } else {
6715 // Position and length encoded in two smis.
6716 Object* obj = fixed_array->get(++i);
6717 ASSERT(obj->IsSmi());
6718 pos = Smi::cast(obj)->value();
6719 len = -encoded_slice;
6720 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006721 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006722 sink + position,
6723 pos,
6724 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006725 position += len;
6726 } else {
6727 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006728 int element_length = string->length();
6729 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006730 position += element_length;
6731 }
6732 }
6733}
6734
6735
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006736RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006737 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006738 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006739 CONVERT_ARG_CHECKED(JSArray, array, 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006740 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006741 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006742 return Failure::OutOfMemoryException();
6743 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006744 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006745 CONVERT_ARG_CHECKED(String, special, 2);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006746
6747 // This assumption is used by the slice encoding in one or two smis.
6748 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6749
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006750 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006751 if (maybe_result->IsFailure()) return maybe_result;
6752
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006753 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006754 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006755 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006756 }
6757 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006758 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006759 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006760 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006761
6762 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006763 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006764 } else if (array_length == 1) {
6765 Object* first = fixed_array->get(0);
6766 if (first->IsString()) return first;
6767 }
6768
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006769 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006770 int position = 0;
6771 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006772 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006773 Object* elt = fixed_array->get(i);
6774 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006775 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006776 int smi_value = Smi::cast(elt)->value();
6777 int pos;
6778 int len;
6779 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006780 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006781 pos = StringBuilderSubstringPosition::decode(smi_value);
6782 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006783 } else {
6784 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006785 len = -smi_value;
6786 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006787 i++;
6788 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006789 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006790 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006791 Object* next_smi = fixed_array->get(i);
6792 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006793 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006794 }
6795 pos = Smi::cast(next_smi)->value();
6796 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006797 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006798 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006799 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006800 ASSERT(pos >= 0);
6801 ASSERT(len >= 0);
6802 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006803 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006804 }
6805 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006806 } else if (elt->IsString()) {
6807 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006808 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006809 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006810 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006811 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006812 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006813 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006814 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006815 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006816 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006817 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006818 return Failure::OutOfMemoryException();
6819 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006820 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006821 }
6822
6823 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006824 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006825
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006826 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006827 { MaybeObject* maybe_object =
6828 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006829 if (!maybe_object->ToObject(&object)) return maybe_object;
6830 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006831 SeqAsciiString* answer = SeqAsciiString::cast(object);
6832 StringBuilderConcatHelper(special,
6833 answer->GetChars(),
6834 fixed_array,
6835 array_length);
6836 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006837 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006838 { MaybeObject* maybe_object =
6839 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006840 if (!maybe_object->ToObject(&object)) return maybe_object;
6841 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006842 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6843 StringBuilderConcatHelper(special,
6844 answer->GetChars(),
6845 fixed_array,
6846 array_length);
6847 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006848 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006849}
6850
6851
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006852RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006853 NoHandleAllocation ha;
6854 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006855 CONVERT_ARG_CHECKED(JSArray, array, 0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006856 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006857 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006858 return Failure::OutOfMemoryException();
6859 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006860 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006861 CONVERT_ARG_CHECKED(String, separator, 2);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006862
6863 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006864 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006865 }
6866 FixedArray* fixed_array = FixedArray::cast(array->elements());
6867 if (fixed_array->length() < array_length) {
6868 array_length = fixed_array->length();
6869 }
6870
6871 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006872 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006873 } else if (array_length == 1) {
6874 Object* first = fixed_array->get(0);
6875 if (first->IsString()) return first;
6876 }
6877
6878 int separator_length = separator->length();
6879 int max_nof_separators =
6880 (String::kMaxLength + separator_length - 1) / separator_length;
6881 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006882 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006883 return Failure::OutOfMemoryException();
6884 }
6885 int length = (array_length - 1) * separator_length;
6886 for (int i = 0; i < array_length; i++) {
6887 Object* element_obj = fixed_array->get(i);
6888 if (!element_obj->IsString()) {
6889 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006890 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006891 }
6892 String* element = String::cast(element_obj);
6893 int increment = element->length();
6894 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006895 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006896 return Failure::OutOfMemoryException();
6897 }
6898 length += increment;
6899 }
6900
6901 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006902 { MaybeObject* maybe_object =
6903 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006904 if (!maybe_object->ToObject(&object)) return maybe_object;
6905 }
6906 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6907
6908 uc16* sink = answer->GetChars();
6909#ifdef DEBUG
6910 uc16* end = sink + length;
6911#endif
6912
6913 String* first = String::cast(fixed_array->get(0));
6914 int first_length = first->length();
6915 String::WriteToFlat(first, sink, 0, first_length);
6916 sink += first_length;
6917
6918 for (int i = 1; i < array_length; i++) {
6919 ASSERT(sink + separator_length <= end);
6920 String::WriteToFlat(separator, sink, 0, separator_length);
6921 sink += separator_length;
6922
6923 String* element = String::cast(fixed_array->get(i));
6924 int element_length = element->length();
6925 ASSERT(sink + element_length <= end);
6926 String::WriteToFlat(element, sink, 0, element_length);
6927 sink += element_length;
6928 }
6929 ASSERT(sink == end);
6930
6931 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6932 return answer;
6933}
6934
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006935template <typename Char>
6936static void JoinSparseArrayWithSeparator(FixedArray* elements,
6937 int elements_length,
6938 uint32_t array_length,
6939 String* separator,
6940 Vector<Char> buffer) {
6941 int previous_separator_position = 0;
6942 int separator_length = separator->length();
6943 int cursor = 0;
6944 for (int i = 0; i < elements_length; i += 2) {
6945 int position = NumberToInt32(elements->get(i));
6946 String* string = String::cast(elements->get(i + 1));
6947 int string_length = string->length();
6948 if (string->length() > 0) {
6949 while (previous_separator_position < position) {
6950 String::WriteToFlat<Char>(separator, &buffer[cursor],
6951 0, separator_length);
6952 cursor += separator_length;
6953 previous_separator_position++;
6954 }
6955 String::WriteToFlat<Char>(string, &buffer[cursor],
6956 0, string_length);
6957 cursor += string->length();
6958 }
6959 }
6960 if (separator_length > 0) {
6961 // Array length must be representable as a signed 32-bit number,
6962 // otherwise the total string length would have been too large.
6963 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6964 int last_array_index = static_cast<int>(array_length - 1);
6965 while (previous_separator_position < last_array_index) {
6966 String::WriteToFlat<Char>(separator, &buffer[cursor],
6967 0, separator_length);
6968 cursor += separator_length;
6969 previous_separator_position++;
6970 }
6971 }
6972 ASSERT(cursor <= buffer.length());
6973}
6974
6975
6976RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6977 NoHandleAllocation ha;
6978 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006979 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006980 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6981 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006982 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006983 CONVERT_ARG_CHECKED(String, separator, 2);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006984 // elements_array is fast-mode JSarray of alternating positions
6985 // (increasing order) and strings.
6986 // array_length is length of original array (used to add separators);
6987 // separator is string to put between elements. Assumed to be non-empty.
6988
6989 // Find total length of join result.
6990 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006991 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006992 int max_string_length;
6993 if (is_ascii) {
6994 max_string_length = SeqAsciiString::kMaxLength;
6995 } else {
6996 max_string_length = SeqTwoByteString::kMaxLength;
6997 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006998 bool overflow = false;
6999 CONVERT_NUMBER_CHECKED(int, elements_length,
7000 Int32, elements_array->length());
7001 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
7002 FixedArray* elements = FixedArray::cast(elements_array->elements());
7003 for (int i = 0; i < elements_length; i += 2) {
7004 RUNTIME_ASSERT(elements->get(i)->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007005 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
7006 String* string = String::cast(elements->get(i + 1));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00007007 int length = string->length();
7008 if (is_ascii && !string->IsAsciiRepresentation()) {
7009 is_ascii = false;
7010 max_string_length = SeqTwoByteString::kMaxLength;
7011 }
7012 if (length > max_string_length ||
7013 max_string_length - length < string_length) {
7014 overflow = true;
7015 break;
7016 }
7017 string_length += length;
7018 }
7019 int separator_length = separator->length();
7020 if (!overflow && separator_length > 0) {
7021 if (array_length <= 0x7fffffffu) {
7022 int separator_count = static_cast<int>(array_length) - 1;
7023 int remaining_length = max_string_length - string_length;
7024 if ((remaining_length / separator_length) >= separator_count) {
7025 string_length += separator_length * (array_length - 1);
7026 } else {
7027 // Not room for the separators within the maximal string length.
7028 overflow = true;
7029 }
7030 } else {
7031 // Nonempty separator and at least 2^31-1 separators necessary
7032 // means that the string is too large to create.
7033 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
7034 overflow = true;
7035 }
7036 }
7037 if (overflow) {
7038 // Throw OutOfMemory exception for creating too large a string.
7039 V8::FatalProcessOutOfMemory("Array join result too large.");
7040 }
7041
7042 if (is_ascii) {
7043 MaybeObject* result_allocation =
7044 isolate->heap()->AllocateRawAsciiString(string_length);
7045 if (result_allocation->IsFailure()) return result_allocation;
7046 SeqAsciiString* result_string =
7047 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
7048 JoinSparseArrayWithSeparator<char>(elements,
7049 elements_length,
7050 array_length,
7051 separator,
7052 Vector<char>(result_string->GetChars(),
7053 string_length));
7054 return result_string;
7055 } else {
7056 MaybeObject* result_allocation =
7057 isolate->heap()->AllocateRawTwoByteString(string_length);
7058 if (result_allocation->IsFailure()) return result_allocation;
7059 SeqTwoByteString* result_string =
7060 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7061 JoinSparseArrayWithSeparator<uc16>(elements,
7062 elements_length,
7063 array_length,
7064 separator,
7065 Vector<uc16>(result_string->GetChars(),
7066 string_length));
7067 return result_string;
7068 }
7069}
7070
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007072RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007073 NoHandleAllocation ha;
7074 ASSERT(args.length() == 2);
7075
7076 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7077 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007078 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007079}
7080
7081
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007082RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007083 NoHandleAllocation ha;
7084 ASSERT(args.length() == 2);
7085
7086 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7087 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007088 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007089}
7090
7091
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007092RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007093 NoHandleAllocation ha;
7094 ASSERT(args.length() == 2);
7095
7096 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7097 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007098 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007099}
7100
7101
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007102RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007103 NoHandleAllocation ha;
7104 ASSERT(args.length() == 1);
7105
7106 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007107 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007108}
7109
7110
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007111RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007112 NoHandleAllocation ha;
7113 ASSERT(args.length() == 2);
7114
7115 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7116 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007117 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007118}
7119
7120
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007121RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007122 NoHandleAllocation ha;
7123 ASSERT(args.length() == 2);
7124
7125 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7126 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007127 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007128}
7129
7130
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007131RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007132 NoHandleAllocation ha;
7133 ASSERT(args.length() == 2);
7134
7135 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7136 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007137 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007138}
7139
7140
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007141RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007142 NoHandleAllocation ha;
7143 ASSERT(args.length() == 2);
7144
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007145 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7146 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007147 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7148 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7149 if (x == y) return Smi::FromInt(EQUAL);
7150 Object* result;
7151 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7152 result = Smi::FromInt(EQUAL);
7153 } else {
7154 result = Smi::FromInt(NOT_EQUAL);
7155 }
7156 return result;
7157}
7158
7159
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007160RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007161 NoHandleAllocation ha;
7162 ASSERT(args.length() == 2);
7163
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007164 CONVERT_ARG_CHECKED(String, x, 0);
7165 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007166
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007167 bool not_equal = !x->Equals(y);
7168 // This is slightly convoluted because the value that signifies
7169 // equality is 0 and inequality is 1 so we have to negate the result
7170 // from String::Equals.
7171 ASSERT(not_equal == 0 || not_equal == 1);
7172 STATIC_CHECK(EQUAL == 0);
7173 STATIC_CHECK(NOT_EQUAL == 1);
7174 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007175}
7176
7177
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007178RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007179 NoHandleAllocation ha;
7180 ASSERT(args.length() == 3);
7181
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007182 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7183 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007184 if (isnan(x) || isnan(y)) return args[2];
7185 if (x == y) return Smi::FromInt(EQUAL);
7186 if (isless(x, y)) return Smi::FromInt(LESS);
7187 return Smi::FromInt(GREATER);
7188}
7189
7190
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007191// Compare two Smis as if they were converted to strings and then
7192// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007193RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007194 NoHandleAllocation ha;
7195 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007196 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7197 CONVERT_SMI_ARG_CHECKED(y_value, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007198
7199 // If the integers are equal so are the string representations.
7200 if (x_value == y_value) return Smi::FromInt(EQUAL);
7201
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007202 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007203 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007204 if (x_value == 0 || y_value == 0)
7205 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007206
ager@chromium.org32912102009-01-16 10:38:43 +00007207 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007208 // smallest because the char code of '-' is less than the char code
7209 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007210
7211 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7212 // architectures using 32-bit Smis.
7213 uint32_t x_scaled = x_value;
7214 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007215 if (x_value < 0 || y_value < 0) {
7216 if (y_value >= 0) return Smi::FromInt(LESS);
7217 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007218 x_scaled = -x_value;
7219 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007220 }
7221
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007222 static const uint32_t kPowersOf10[] = {
7223 1, 10, 100, 1000, 10*1000, 100*1000,
7224 1000*1000, 10*1000*1000, 100*1000*1000,
7225 1000*1000*1000
7226 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007227
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007228 // If the integers have the same number of decimal digits they can be
7229 // compared directly as the numeric order is the same as the
7230 // lexicographic order. If one integer has fewer digits, it is scaled
7231 // by some power of 10 to have the same number of digits as the longer
7232 // integer. If the scaled integers are equal it means the shorter
7233 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007234
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007235 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7236 int x_log2 = IntegerLog2(x_scaled);
7237 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7238 x_log10 -= x_scaled < kPowersOf10[x_log10];
7239
7240 int y_log2 = IntegerLog2(y_scaled);
7241 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7242 y_log10 -= y_scaled < kPowersOf10[y_log10];
7243
7244 int tie = EQUAL;
7245
7246 if (x_log10 < y_log10) {
7247 // X has fewer digits. We would like to simply scale up X but that
7248 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7249 // be scaled up to 9_000_000_000. So we scale up by the next
7250 // smallest power and scale down Y to drop one digit. It is OK to
7251 // drop one digit from the longer integer since the final digit is
7252 // past the length of the shorter integer.
7253 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7254 y_scaled /= 10;
7255 tie = LESS;
7256 } else if (y_log10 < x_log10) {
7257 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7258 x_scaled /= 10;
7259 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007260 }
7261
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007262 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7263 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7264 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007265}
7266
7267
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007268static Object* StringInputBufferCompare(RuntimeState* state,
7269 String* x,
7270 String* y) {
7271 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7272 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007273 bufx.Reset(x);
7274 bufy.Reset(y);
7275 while (bufx.has_more() && bufy.has_more()) {
7276 int d = bufx.GetNext() - bufy.GetNext();
7277 if (d < 0) return Smi::FromInt(LESS);
7278 else if (d > 0) return Smi::FromInt(GREATER);
7279 }
7280
7281 // x is (non-trivial) prefix of y:
7282 if (bufy.has_more()) return Smi::FromInt(LESS);
7283 // y is prefix of x:
7284 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7285}
7286
7287
7288static Object* FlatStringCompare(String* x, String* y) {
7289 ASSERT(x->IsFlat());
7290 ASSERT(y->IsFlat());
7291 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7292 int prefix_length = x->length();
7293 if (y->length() < prefix_length) {
7294 prefix_length = y->length();
7295 equal_prefix_result = Smi::FromInt(GREATER);
7296 } else if (y->length() > prefix_length) {
7297 equal_prefix_result = Smi::FromInt(LESS);
7298 }
7299 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007300 String::FlatContent x_content = x->GetFlatContent();
7301 String::FlatContent y_content = y->GetFlatContent();
7302 if (x_content.IsAscii()) {
7303 Vector<const char> x_chars = x_content.ToAsciiVector();
7304 if (y_content.IsAscii()) {
7305 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007306 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007307 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007308 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007309 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7310 }
7311 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007312 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7313 if (y_content.IsAscii()) {
7314 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007315 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7316 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007317 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007318 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7319 }
7320 }
7321 Object* result;
7322 if (r == 0) {
7323 result = equal_prefix_result;
7324 } else {
7325 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7326 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007327 ASSERT(result ==
7328 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007329 return result;
7330}
7331
7332
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007333RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007334 NoHandleAllocation ha;
7335 ASSERT(args.length() == 2);
7336
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007337 CONVERT_ARG_CHECKED(String, x, 0);
7338 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007339
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007340 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007341
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007342 // A few fast case tests before we flatten.
7343 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007344 if (y->length() == 0) {
7345 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007346 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007347 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007348 return Smi::FromInt(LESS);
7349 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007350
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007351 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007352 if (d < 0) return Smi::FromInt(LESS);
7353 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007354
lrn@chromium.org303ada72010-10-27 09:33:13 +00007355 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007356 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007357 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7358 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007359 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007360 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7361 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007362
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007363 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007364 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007365}
7366
7367
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007368RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007369 NoHandleAllocation ha;
7370 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007371 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007372
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007373 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007374 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007375}
7376
7377
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007378RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007379 NoHandleAllocation ha;
7380 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007381 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007382
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007383 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007384 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007385}
7386
7387
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007388RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007389 NoHandleAllocation ha;
7390 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007391 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007392
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007393 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007394 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007395}
7396
7397
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007398static const double kPiDividedBy4 = 0.78539816339744830962;
7399
7400
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007401RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007402 NoHandleAllocation ha;
7403 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007404 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007405
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007406 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7407 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007408 double result;
7409 if (isinf(x) && isinf(y)) {
7410 // Make sure that the result in case of two infinite arguments
7411 // is a multiple of Pi / 4. The sign of the result is determined
7412 // by the first argument (x) and the sign of the second argument
7413 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007414 int multiplier = (x < 0) ? -1 : 1;
7415 if (y < 0) multiplier *= 3;
7416 result = multiplier * kPiDividedBy4;
7417 } else {
7418 result = atan2(x, y);
7419 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007420 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007421}
7422
7423
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007424RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007425 NoHandleAllocation ha;
7426 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007427 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007428
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007429 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007430 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007431}
7432
7433
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007434RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007435 NoHandleAllocation ha;
7436 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007437 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007438
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007439 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007440 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007441}
7442
7443
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007444RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007445 NoHandleAllocation ha;
7446 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007447 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007448
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007449 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007450 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007451}
7452
7453
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007454RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007455 NoHandleAllocation ha;
7456 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007457 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007458
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007459 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007460 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007461}
7462
7463
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007464RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007465 NoHandleAllocation ha;
7466 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007467 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007468
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007469 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007470 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007471}
7472
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007473// Slow version of Math.pow. We check for fast paths for special cases.
7474// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007475RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007476 NoHandleAllocation ha;
7477 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007478 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007479
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007480 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007481
7482 // If the second argument is a smi, it is much faster to call the
7483 // custom powi() function than the generic pow().
7484 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007485 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007486 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007487 }
7488
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007489 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007490 int y_int = static_cast<int>(y);
7491 double result;
7492 if (y == y_int) {
7493 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7494 } else if (y == 0.5) {
7495 result = (isinf(x)) ? V8_INFINITY : sqrt(x + 0.0); // Convert -0 to +0.
7496 } else if (y == -0.5) {
7497 result = (isinf(x)) ? 0 : 1.0 / sqrt(x + 0.0); // Convert -0 to +0.
7498 } else {
7499 result = power_double_double(x, y);
7500 }
7501 if (isnan(result)) return isolate->heap()->nan_value();
7502 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007503}
7504
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007505// 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 +00007506// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007507RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007508 NoHandleAllocation ha;
7509 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007510 isolate->counters()->math_pow()->Increment();
7511
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007512 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7513 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007514 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007515 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007516 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007517 double result = power_double_double(x, y);
7518 if (isnan(result)) return isolate->heap()->nan_value();
7519 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007520 }
7521}
7522
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007523
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007524RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007525 NoHandleAllocation ha;
7526 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007527 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007528
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007529 if (!args[0]->IsHeapNumber()) {
7530 // Must be smi. Return the argument unchanged for all the other types
7531 // to make fuzz-natives test happy.
7532 return args[0];
7533 }
7534
7535 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7536
7537 double value = number->value();
7538 int exponent = number->get_exponent();
7539 int sign = number->get_sign();
7540
danno@chromium.org160a7b02011-04-18 15:51:38 +00007541 if (exponent < -1) {
7542 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7543 if (sign) return isolate->heap()->minus_zero_value();
7544 return Smi::FromInt(0);
7545 }
7546
7547 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7548 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007549 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007550 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007551 return Smi::FromInt(static_cast<int>(value + 0.5));
7552 }
7553
7554 // If the magnitude is big enough, there's no place for fraction part. If we
7555 // try to add 0.5 to this number, 1.0 will be added instead.
7556 if (exponent >= 52) {
7557 return number;
7558 }
7559
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007560 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007561
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007562 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007563 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007564}
7565
7566
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007567RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007568 NoHandleAllocation ha;
7569 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007570 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007571
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007572 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007573 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007574}
7575
7576
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007577RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007578 NoHandleAllocation ha;
7579 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007580 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007581
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007582 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007583 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007584}
7585
7586
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007587RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007588 NoHandleAllocation ha;
7589 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007590 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007591
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007592 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007593 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007594}
7595
7596
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007597static int MakeDay(int year, int month) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007598 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7599 181, 212, 243, 273, 304, 334};
7600 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7601 182, 213, 244, 274, 305, 335};
7602
7603 year += month / 12;
7604 month %= 12;
7605 if (month < 0) {
7606 year--;
7607 month += 12;
7608 }
7609
7610 ASSERT(month >= 0);
7611 ASSERT(month < 12);
7612
7613 // year_delta is an arbitrary number such that:
7614 // a) year_delta = -1 (mod 400)
7615 // b) year + year_delta > 0 for years in the range defined by
7616 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7617 // Jan 1 1970. This is required so that we don't run into integer
7618 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007619 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007620 // operations.
7621 static const int year_delta = 399999;
7622 static const int base_day = 365 * (1970 + year_delta) +
7623 (1970 + year_delta) / 4 -
7624 (1970 + year_delta) / 100 +
7625 (1970 + year_delta) / 400;
7626
7627 int year1 = year + year_delta;
7628 int day_from_year = 365 * year1 +
7629 year1 / 4 -
7630 year1 / 100 +
7631 year1 / 400 -
7632 base_day;
7633
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007634 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
7635 return day_from_year + day_from_month[month];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007636 }
7637
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007638 return day_from_year + day_from_month_leap[month];
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007639}
7640
7641
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007642RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007643 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007644 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007645
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007646 CONVERT_SMI_ARG_CHECKED(year, 0);
7647 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007648
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007649 return Smi::FromInt(MakeDay(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007650}
7651
7652
7653static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7654static const int kDaysIn4Years = 4 * 365 + 1;
7655static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7656static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7657static const int kDays1970to2000 = 30 * 365 + 7;
7658static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7659 kDays1970to2000;
7660static const int kYearsOffset = 400000;
7661
7662static const char kDayInYear[] = {
7663 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7664 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7665 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7666 22, 23, 24, 25, 26, 27, 28,
7667 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7668 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7669 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7670 22, 23, 24, 25, 26, 27, 28, 29, 30,
7671 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7672 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7673 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7674 22, 23, 24, 25, 26, 27, 28, 29, 30,
7675 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7676 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7677 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7678 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7679 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7680 22, 23, 24, 25, 26, 27, 28, 29, 30,
7681 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7682 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7683 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7684 22, 23, 24, 25, 26, 27, 28, 29, 30,
7685 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7686 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7687
7688 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7689 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7690 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7691 22, 23, 24, 25, 26, 27, 28,
7692 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7693 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7694 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7695 22, 23, 24, 25, 26, 27, 28, 29, 30,
7696 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7697 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7698 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7699 22, 23, 24, 25, 26, 27, 28, 29, 30,
7700 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7701 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7702 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7703 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7704 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7705 22, 23, 24, 25, 26, 27, 28, 29, 30,
7706 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7707 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7708 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7709 22, 23, 24, 25, 26, 27, 28, 29, 30,
7710 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7711 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7712
7713 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7714 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7715 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7716 22, 23, 24, 25, 26, 27, 28, 29,
7717 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7718 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7719 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7720 22, 23, 24, 25, 26, 27, 28, 29, 30,
7721 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7722 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7723 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7724 22, 23, 24, 25, 26, 27, 28, 29, 30,
7725 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7726 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7727 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7728 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7729 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7730 22, 23, 24, 25, 26, 27, 28, 29, 30,
7731 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7732 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7733 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7734 22, 23, 24, 25, 26, 27, 28, 29, 30,
7735 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7736 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7737
7738 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7739 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7740 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7741 22, 23, 24, 25, 26, 27, 28,
7742 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7743 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7744 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7745 22, 23, 24, 25, 26, 27, 28, 29, 30,
7746 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7747 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7748 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7749 22, 23, 24, 25, 26, 27, 28, 29, 30,
7750 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7751 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7752 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7753 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7754 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7755 22, 23, 24, 25, 26, 27, 28, 29, 30,
7756 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7757 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7758 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7759 22, 23, 24, 25, 26, 27, 28, 29, 30,
7760 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7761 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7762
7763static const char kMonthInYear[] = {
7764 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7765 0, 0, 0, 0, 0, 0,
7766 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7767 1, 1, 1,
7768 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7769 2, 2, 2, 2, 2, 2,
7770 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7771 3, 3, 3, 3, 3,
7772 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7773 4, 4, 4, 4, 4, 4,
7774 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7775 5, 5, 5, 5, 5,
7776 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7777 6, 6, 6, 6, 6, 6,
7778 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7779 7, 7, 7, 7, 7, 7,
7780 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7781 8, 8, 8, 8, 8,
7782 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7783 9, 9, 9, 9, 9, 9,
7784 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7785 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7786 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7787 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7788
7789 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7790 0, 0, 0, 0, 0, 0,
7791 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7792 1, 1, 1,
7793 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7794 2, 2, 2, 2, 2, 2,
7795 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7796 3, 3, 3, 3, 3,
7797 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7798 4, 4, 4, 4, 4, 4,
7799 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7800 5, 5, 5, 5, 5,
7801 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7802 6, 6, 6, 6, 6, 6,
7803 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7804 7, 7, 7, 7, 7, 7,
7805 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7806 8, 8, 8, 8, 8,
7807 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7808 9, 9, 9, 9, 9, 9,
7809 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7810 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7811 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7812 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7813
7814 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7815 0, 0, 0, 0, 0, 0,
7816 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7817 1, 1, 1, 1,
7818 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7819 2, 2, 2, 2, 2, 2,
7820 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7821 3, 3, 3, 3, 3,
7822 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7823 4, 4, 4, 4, 4, 4,
7824 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7825 5, 5, 5, 5, 5,
7826 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7827 6, 6, 6, 6, 6, 6,
7828 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7829 7, 7, 7, 7, 7, 7,
7830 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7831 8, 8, 8, 8, 8,
7832 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7833 9, 9, 9, 9, 9, 9,
7834 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7835 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7836 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7837 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7838
7839 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7840 0, 0, 0, 0, 0, 0,
7841 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7842 1, 1, 1,
7843 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7844 2, 2, 2, 2, 2, 2,
7845 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7846 3, 3, 3, 3, 3,
7847 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7848 4, 4, 4, 4, 4, 4,
7849 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7850 5, 5, 5, 5, 5,
7851 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7852 6, 6, 6, 6, 6, 6,
7853 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7854 7, 7, 7, 7, 7, 7,
7855 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7856 8, 8, 8, 8, 8,
7857 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7858 9, 9, 9, 9, 9, 9,
7859 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7860 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7861 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7862 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7863
7864
7865// This function works for dates from 1970 to 2099.
7866static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007867 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007868#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007869 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007870#endif
7871
7872 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7873 date %= kDaysIn4Years;
7874
7875 month = kMonthInYear[date];
7876 day = kDayInYear[date];
7877
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007878 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007879}
7880
7881
7882static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007883 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007884#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007885 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007886#endif
7887
7888 date += kDaysOffset;
7889 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7890 date %= kDaysIn400Years;
7891
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007892 ASSERT(MakeDay(year, 0) + date == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007893
7894 date--;
7895 int yd1 = date / kDaysIn100Years;
7896 date %= kDaysIn100Years;
7897 year += 100 * yd1;
7898
7899 date++;
7900 int yd2 = date / kDaysIn4Years;
7901 date %= kDaysIn4Years;
7902 year += 4 * yd2;
7903
7904 date--;
7905 int yd3 = date / 365;
7906 date %= 365;
7907 year += yd3;
7908
7909 bool is_leap = (!yd1 || yd2) && !yd3;
7910
7911 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007912 ASSERT(is_leap || (date >= 0));
7913 ASSERT((date < 365) || (is_leap && (date < 366)));
7914 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007915 ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
7916 ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007917
7918 if (is_leap) {
7919 day = kDayInYear[2*365 + 1 + date];
7920 month = kMonthInYear[2*365 + 1 + date];
7921 } else {
7922 day = kDayInYear[date];
7923 month = kMonthInYear[date];
7924 }
7925
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007926 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007927}
7928
7929
7930static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007931 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007932 if (date >= 0 && date < 32 * kDaysIn4Years) {
7933 DateYMDFromTimeAfter1970(date, year, month, day);
7934 } else {
7935 DateYMDFromTimeSlow(date, year, month, day);
7936 }
7937}
7938
7939
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007940RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007941 NoHandleAllocation ha;
7942 ASSERT(args.length() == 2);
7943
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007944 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007945 CONVERT_ARG_CHECKED(JSArray, res_array, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007946
7947 int year, month, day;
7948 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7949
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007950 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7951 RUNTIME_ASSERT(elms_base->length() == 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007952 RUNTIME_ASSERT(res_array->HasFastTypeElements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007953
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007954 MaybeObject* maybe = res_array->EnsureWritableFastElements();
7955 if (maybe->IsFailure()) return maybe;
7956 FixedArray* elms = FixedArray::cast(res_array->elements());
7957 elms->set(0, Smi::FromInt(year));
7958 elms->set(1, Smi::FromInt(month));
7959 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007960
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007961 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007962}
7963
7964
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007965RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007966 HandleScope scope(isolate);
7967 ASSERT(args.length() == 3);
7968
7969 Handle<JSFunction> callee = args.at<JSFunction>(0);
7970 Object** parameters = reinterpret_cast<Object**>(args[1]);
7971 const int argument_count = Smi::cast(args[2])->value();
7972
7973 Handle<JSObject> result =
7974 isolate->factory()->NewArgumentsObject(callee, argument_count);
7975 // Allocate the elements if needed.
7976 int parameter_count = callee->shared()->formal_parameter_count();
7977 if (argument_count > 0) {
7978 if (parameter_count > 0) {
7979 int mapped_count = Min(argument_count, parameter_count);
7980 Handle<FixedArray> parameter_map =
7981 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7982 parameter_map->set_map(
7983 isolate->heap()->non_strict_arguments_elements_map());
7984
7985 Handle<Map> old_map(result->map());
7986 Handle<Map> new_map =
7987 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007988 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007989
7990 result->set_map(*new_map);
7991 result->set_elements(*parameter_map);
7992
7993 // Store the context and the arguments array at the beginning of the
7994 // parameter map.
7995 Handle<Context> context(isolate->context());
7996 Handle<FixedArray> arguments =
7997 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7998 parameter_map->set(0, *context);
7999 parameter_map->set(1, *arguments);
8000
8001 // Loop over the actual parameters backwards.
8002 int index = argument_count - 1;
8003 while (index >= mapped_count) {
8004 // These go directly in the arguments array and have no
8005 // corresponding slot in the parameter map.
8006 arguments->set(index, *(parameters - index - 1));
8007 --index;
8008 }
8009
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008010 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00008011 while (index >= 0) {
8012 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008013 Handle<String> name(scope_info->ParameterName(index));
8014 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00008015 bool duplicate = false;
8016 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008017 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008018 duplicate = true;
8019 break;
8020 }
8021 }
8022
8023 if (duplicate) {
8024 // This goes directly in the arguments array with a hole in the
8025 // parameter map.
8026 arguments->set(index, *(parameters - index - 1));
8027 parameter_map->set_the_hole(index + 2);
8028 } else {
8029 // The context index goes in the parameter map with a hole in the
8030 // arguments array.
8031 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008032 for (int j = 0; j < context_local_count; ++j) {
8033 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008034 context_index = j;
8035 break;
8036 }
8037 }
8038 ASSERT(context_index >= 0);
8039 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008040 parameter_map->set(index + 2, Smi::FromInt(
8041 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00008042 }
8043
8044 --index;
8045 }
8046 } else {
8047 // If there is no aliasing, the arguments object elements are not
8048 // special in any way.
8049 Handle<FixedArray> elements =
8050 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
8051 result->set_elements(*elements);
8052 for (int i = 0; i < argument_count; ++i) {
8053 elements->set(i, *(parameters - i - 1));
8054 }
8055 }
8056 }
8057 return *result;
8058}
8059
8060
8061RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008062 NoHandleAllocation ha;
8063 ASSERT(args.length() == 3);
8064
8065 JSFunction* callee = JSFunction::cast(args[0]);
8066 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008067 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008068
lrn@chromium.org303ada72010-10-27 09:33:13 +00008069 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008070 { MaybeObject* maybe_result =
8071 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008072 if (!maybe_result->ToObject(&result)) return maybe_result;
8073 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008074 // Allocate the elements if needed.
8075 if (length > 0) {
8076 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008077 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008078 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008079 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8080 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008081
8082 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008083 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008084 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008085 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008086
8087 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008088 for (int i = 0; i < length; i++) {
8089 array->set(i, *--parameters, mode);
8090 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008091 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008092 }
8093 return result;
8094}
8095
8096
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008097RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008098 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008099 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008100 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8101 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
8102 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008103
whesse@chromium.org7b260152011-06-20 15:33:18 +00008104 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008105 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008106 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008107 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008108 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8109 context,
8110 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008111 return *result;
8112}
8113
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008114
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008115// Find the arguments of the JavaScript function invocation that called
8116// into C++ code. Collect these in a newly allocated array of handles (possibly
8117// prefixed by a number of empty handles).
8118static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8119 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008120 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008121 // Find frame containing arguments passed to the caller.
8122 JavaScriptFrameIterator it;
8123 JavaScriptFrame* frame = it.frame();
8124 List<JSFunction*> functions(2);
8125 frame->GetFunctions(&functions);
8126 if (functions.length() > 1) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008127 int inlined_jsframe_index = functions.length() - 1;
8128 JSFunction* inlined_function = functions[inlined_jsframe_index];
8129 Vector<SlotRef> args_slots =
8130 SlotRef::ComputeSlotMappingForArguments(
8131 frame,
8132 inlined_jsframe_index,
8133 inlined_function->shared()->formal_parameter_count());
8134
8135 int args_count = args_slots.length();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008136
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008137 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008138 SmartArrayPointer<Handle<Object> > param_data(
8139 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008140 for (int i = 0; i < args_count; i++) {
8141 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008142 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008143 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008144
8145 args_slots.Dispose();
8146
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008147 return param_data;
8148 } else {
8149 it.AdvanceToArgumentsFrame();
8150 frame = it.frame();
8151 int args_count = frame->ComputeParametersCount();
8152
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008153 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008154 SmartArrayPointer<Handle<Object> > param_data(
8155 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008156 for (int i = 0; i < args_count; i++) {
8157 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008158 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008159 }
8160 return param_data;
8161 }
8162}
8163
8164
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008165RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8166 HandleScope scope(isolate);
8167 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008168 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008169 RUNTIME_ASSERT(args[3]->IsNumber());
8170 Handle<Object> bindee = args.at<Object>(1);
8171
8172 // TODO(lrn): Create bound function in C++ code from premade shared info.
8173 bound_function->shared()->set_bound(true);
8174 // Get all arguments of calling function (Function.prototype.bind).
8175 int argc = 0;
8176 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8177 // Don't count the this-arg.
8178 if (argc > 0) {
8179 ASSERT(*arguments[0] == args[2]);
8180 argc--;
8181 } else {
8182 ASSERT(args[2]->IsUndefined());
8183 }
8184 // Initialize array of bindings (function, this, and any existing arguments
8185 // if the function was already bound).
8186 Handle<FixedArray> new_bindings;
8187 int i;
8188 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8189 Handle<FixedArray> old_bindings(
8190 JSFunction::cast(*bindee)->function_bindings());
8191 new_bindings =
8192 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8193 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8194 i = 0;
8195 for (int n = old_bindings->length(); i < n; i++) {
8196 new_bindings->set(i, old_bindings->get(i));
8197 }
8198 } else {
8199 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8200 new_bindings = isolate->factory()->NewFixedArray(array_size);
8201 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8202 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8203 i = 2;
8204 }
8205 // Copy arguments, skipping the first which is "this_arg".
8206 for (int j = 0; j < argc; j++, i++) {
8207 new_bindings->set(i, *arguments[j + 1]);
8208 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008209 new_bindings->set_map_no_write_barrier(
8210 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008211 bound_function->set_function_bindings(*new_bindings);
8212
8213 // Update length.
8214 Handle<String> length_symbol = isolate->factory()->length_symbol();
8215 Handle<Object> new_length(args.at<Object>(3));
8216 PropertyAttributes attr =
8217 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8218 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8219 return *bound_function;
8220}
8221
8222
8223RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8224 HandleScope handles(isolate);
8225 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008226 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008227 if (callable->IsJSFunction()) {
8228 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8229 if (function->shared()->bound()) {
8230 Handle<FixedArray> bindings(function->function_bindings());
8231 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8232 return *isolate->factory()->NewJSArrayWithElements(bindings);
8233 }
8234 }
8235 return isolate->heap()->undefined_value();
8236}
8237
8238
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008239RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008240 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008241 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008242 // First argument is a function to use as a constructor.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008243 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008244 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008245
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008246 // The argument is a bound function. Extract its bound arguments
8247 // and callable.
8248 Handle<FixedArray> bound_args =
8249 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8250 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8251 Handle<Object> bound_function(
8252 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8253 ASSERT(!bound_function->IsJSFunction() ||
8254 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008256 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008257 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008258 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008259 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008260 param_data[i] = Handle<Object>(bound_args->get(
8261 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008262 }
8263
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008264 if (!bound_function->IsJSFunction()) {
8265 bool exception_thrown;
8266 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8267 &exception_thrown);
8268 if (exception_thrown) return Failure::Exception();
8269 }
8270 ASSERT(bound_function->IsJSFunction());
8271
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008272 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008273 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008274 Execution::New(Handle<JSFunction>::cast(bound_function),
8275 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008276 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008277 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008278 }
8279 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008280 return *result;
8281}
8282
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008283
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008284static void TrySettingInlineConstructStub(Isolate* isolate,
8285 Handle<JSFunction> function) {
8286 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008287 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008288 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008289 }
8290 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008291 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008292 Handle<Code> code = compiler.CompileConstructStub(function);
8293 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008294 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008295}
8296
8297
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008298RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008299 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008300 ASSERT(args.length() == 1);
8301
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008302 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008303
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008304 // If the constructor isn't a proper function we throw a type error.
8305 if (!constructor->IsJSFunction()) {
8306 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8307 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008308 isolate->factory()->NewTypeError("not_constructor", arguments);
8309 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008310 }
8311
8312 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008313
8314 // If function should not have prototype, construction is not allowed. In this
8315 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008316 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008317 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8318 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008319 isolate->factory()->NewTypeError("not_constructor", arguments);
8320 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008321 }
8322
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008323#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008324 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008325 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008326 if (debug->StepInActive()) {
8327 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008328 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008329#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008330
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008331 if (function->has_initial_map()) {
8332 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008333 // The 'Function' function ignores the receiver object when
8334 // called using 'new' and creates a new JSFunction object that
8335 // is returned. The receiver object is only used for error
8336 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008337 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008338 // allocate JSFunctions since it does not properly initialize
8339 // the shared part of the function. Since the receiver is
8340 // ignored anyway, we use the global object as the receiver
8341 // instead of a new JSFunction object. This way, errors are
8342 // reported the same way whether or not 'Function' is called
8343 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008344 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008345 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008346 }
8347
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008348 // The function should be compiled for the optimization hints to be
8349 // available. We cannot use EnsureCompiled because that forces a
8350 // compilation through the shared function info which makes it
8351 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008352 if (!function->is_compiled()) {
8353 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8354 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008355
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008356 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008357 if (!function->has_initial_map() &&
8358 shared->IsInobjectSlackTrackingInProgress()) {
8359 // The tracking is already in progress for another function. We can only
8360 // track one initial_map at a time, so we force the completion before the
8361 // function is called as a constructor for the first time.
8362 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008363 }
8364
8365 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008366 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8367 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008368 // Delay setting the stub if inobject slack tracking is in progress.
8369 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008370 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008371 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008372
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008373 isolate->counters()->constructed_objects()->Increment();
8374 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008375
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008376 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008377}
8378
8379
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008380RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008381 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008382 ASSERT(args.length() == 1);
8383
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008384 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008385 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008386 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008387
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008388 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008389}
8390
8391
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008392RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008393 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008394 ASSERT(args.length() == 1);
8395
8396 Handle<JSFunction> function = args.at<JSFunction>(0);
8397#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008398 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008399 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008400 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008401 PrintF("]\n");
8402 }
8403#endif
8404
lrn@chromium.org34e60782011-09-15 07:25:40 +00008405 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008406 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008407 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008408 return Failure::Exception();
8409 }
8410
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008411 // All done. Return the compiled code.
8412 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008413 return function->code();
8414}
8415
8416
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008417RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008418 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008419 ASSERT(args.length() == 1);
8420 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008421
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00008422 function->shared()->set_profiler_ticks(0);
8423
lrn@chromium.org34e60782011-09-15 07:25:40 +00008424 // If the function is not compiled ignore the lazy
8425 // recompilation. This can happen if the debugger is activated and
8426 // the function is returned to the not compiled state.
8427 if (!function->shared()->is_compiled()) {
8428 function->ReplaceCode(function->shared()->code());
8429 return function->code();
8430 }
8431
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008432 // If the function is not optimizable or debugger is active continue using the
8433 // code from the full compiler.
8434 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008435 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008436 if (FLAG_trace_opt) {
8437 PrintF("[failed to optimize ");
8438 function->PrintName();
8439 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8440 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008441 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008442 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008443 function->ReplaceCode(function->shared()->code());
8444 return function->code();
8445 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008446 if (JSFunction::CompileOptimized(function,
8447 AstNode::kNoNumber,
8448 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008449 return function->code();
8450 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008451 if (FLAG_trace_opt) {
8452 PrintF("[failed to optimize ");
8453 function->PrintName();
8454 PrintF(": optimized compilation failed]\n");
8455 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008456 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008457 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008458}
8459
8460
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008461class ActivationsFinder : public ThreadVisitor {
8462 public:
8463 explicit ActivationsFinder(JSFunction* function)
8464 : function_(function), has_activations_(false) {}
8465
8466 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8467 if (has_activations_) return;
8468
8469 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8470 JavaScriptFrame* frame = it.frame();
8471 if (frame->is_optimized() && frame->function() == function_) {
8472 has_activations_ = true;
8473 return;
8474 }
8475 }
8476 }
8477
8478 bool has_activations() { return has_activations_; }
8479
8480 private:
8481 JSFunction* function_;
8482 bool has_activations_;
8483};
8484
8485
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008486RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008487 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008488 ASSERT(args.length() == 1);
8489 RUNTIME_ASSERT(args[0]->IsSmi());
8490 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008491 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008492 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8493 ASSERT(isolate->heap()->IsAllocationAllowed());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008494 int jsframes = deoptimizer->jsframe_count();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008495
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008496 deoptimizer->MaterializeHeapNumbers();
8497 delete deoptimizer;
8498
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008499 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008500 JavaScriptFrame* frame = NULL;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008501 for (int i = 0; i < jsframes - 1; i++) it.Advance();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008502 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008503
8504 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008505 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008506 Handle<Object> arguments;
8507 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008508 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008509 if (arguments.is_null()) {
8510 // FunctionGetArguments can't throw an exception, so cast away the
8511 // doubt with an assert.
8512 arguments = Handle<Object>(
8513 Accessors::FunctionGetArguments(*function,
8514 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008515 ASSERT(*arguments != isolate->heap()->null_value());
8516 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008517 }
8518 frame->SetExpression(i, *arguments);
8519 }
8520 }
8521
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008522 if (type == Deoptimizer::EAGER) {
8523 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008524 }
8525
8526 // Avoid doing too much work when running with --always-opt and keep
8527 // the optimized code around.
8528 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008529 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008530 }
8531
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008532 // Find other optimized activations of the function.
8533 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008534 while (!it.done()) {
8535 JavaScriptFrame* frame = it.frame();
8536 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008537 has_other_activations = true;
8538 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008539 }
8540 it.Advance();
8541 }
8542
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008543 if (!has_other_activations) {
8544 ActivationsFinder activations_finder(*function);
8545 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8546 has_other_activations = activations_finder.has_activations();
8547 }
8548
8549 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008550 if (FLAG_trace_deopt) {
8551 PrintF("[removing optimized code for: ");
8552 function->PrintName();
8553 PrintF("]\n");
8554 }
8555 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008556 } else {
8557 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008558 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008559 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008560}
8561
8562
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008563RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008564 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008565 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008566 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008567}
8568
8569
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008570RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008571 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008572 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008573 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008574 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008575
8576 Deoptimizer::DeoptimizeFunction(*function);
8577
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008578 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008579}
8580
8581
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008582RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8583#if defined(USE_SIMULATOR)
8584 return isolate->heap()->true_value();
8585#else
8586 return isolate->heap()->false_value();
8587#endif
8588}
8589
8590
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008591RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8592 HandleScope scope(isolate);
8593 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008594 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008595 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8596 function->MarkForLazyRecompilation();
8597 return isolate->heap()->undefined_value();
8598}
8599
8600
lrn@chromium.org1c092762011-05-09 09:42:16 +00008601RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8602 HandleScope scope(isolate);
8603 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008604 // The least significant bit (after untagging) indicates whether the
8605 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008606 if (!V8::UseCrankshaft()) {
8607 return Smi::FromInt(4); // 4 == "never".
8608 }
8609 if (FLAG_always_opt) {
8610 return Smi::FromInt(3); // 3 == "always".
8611 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008612 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008613 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8614 : Smi::FromInt(2); // 2 == "no".
8615}
8616
8617
8618RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8619 HandleScope scope(isolate);
8620 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008621 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008622 return Smi::FromInt(function->shared()->opt_count());
8623}
8624
8625
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008626RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008627 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008628 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008629 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008630
8631 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008632 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008633
8634 // We have hit a back edge in an unoptimized frame for a function that was
8635 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008636 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008637 // Keep track of whether we've succeeded in optimizing.
8638 bool succeeded = unoptimized->optimizable();
8639 if (succeeded) {
8640 // If we are trying to do OSR when there are already optimized
8641 // activations of the function, it means (a) the function is directly or
8642 // indirectly recursive and (b) an optimized invocation has been
8643 // deoptimized so that we are currently in an unoptimized activation.
8644 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008645 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008646 while (succeeded && !it.done()) {
8647 JavaScriptFrame* frame = it.frame();
8648 succeeded = !frame->is_optimized() || frame->function() != *function;
8649 it.Advance();
8650 }
8651 }
8652
8653 int ast_id = AstNode::kNoNumber;
8654 if (succeeded) {
8655 // The top JS function is this one, the PC is somewhere in the
8656 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008657 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008658 JavaScriptFrame* frame = it.frame();
8659 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008660 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008661 ASSERT(unoptimized->contains(frame->pc()));
8662
8663 // Use linear search of the unoptimized code's stack check table to find
8664 // the AST id matching the PC.
8665 Address start = unoptimized->instruction_start();
8666 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008667 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008668 uint32_t table_length = Memory::uint32_at(table_cursor);
8669 table_cursor += kIntSize;
8670 for (unsigned i = 0; i < table_length; ++i) {
8671 // Table entries are (AST id, pc offset) pairs.
8672 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8673 if (pc_offset == target_pc_offset) {
8674 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8675 break;
8676 }
8677 table_cursor += 2 * kIntSize;
8678 }
8679 ASSERT(ast_id != AstNode::kNoNumber);
8680 if (FLAG_trace_osr) {
8681 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8682 function->PrintName();
8683 PrintF("]\n");
8684 }
8685
8686 // Try to compile the optimized code. A true return value from
8687 // CompileOptimized means that compilation succeeded, not necessarily
8688 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008689 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008690 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008691 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8692 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008693 if (data->OsrPcOffset()->value() >= 0) {
8694 if (FLAG_trace_osr) {
8695 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008696 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008697 }
8698 ASSERT(data->OsrAstId()->value() == ast_id);
8699 } else {
8700 // We may never generate the desired OSR entry if we emit an
8701 // early deoptimize.
8702 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008703 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008704 } else {
8705 succeeded = false;
8706 }
8707 }
8708
8709 // Revert to the original stack checks in the original unoptimized code.
8710 if (FLAG_trace_osr) {
8711 PrintF("[restoring original stack checks in ");
8712 function->PrintName();
8713 PrintF("]\n");
8714 }
yangguo@chromium.org56454712012-02-16 15:33:53 +00008715 Handle<Code> check_code;
8716#ifdef V8_TARGET_ARCH_IA32
8717 if (FLAG_count_based_interrupts) {
8718 InterruptStub interrupt_stub;
8719 check_code = interrupt_stub.GetCode();
8720 } else // NOLINT
8721#endif
8722 { // NOLINT
8723 StackCheckStub check_stub;
8724 check_code = check_stub.GetCode();
8725 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008726 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008727 Deoptimizer::RevertStackCheckCode(*unoptimized,
8728 *check_code,
8729 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008730
8731 // Allow OSR only at nesting level zero again.
8732 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8733
8734 // If the optimization attempt succeeded, return the AST id tagged as a
8735 // smi. This tells the builtin that we need to translate the unoptimized
8736 // frame to an optimized one.
8737 if (succeeded) {
8738 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8739 return Smi::FromInt(ast_id);
8740 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008741 if (function->IsMarkedForLazyRecompilation()) {
8742 function->ReplaceCode(function->shared()->code());
8743 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008744 return Smi::FromInt(-1);
8745 }
8746}
8747
8748
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008749RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8750 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8751 return isolate->heap()->undefined_value();
8752}
8753
8754
danno@chromium.orgc612e022011-11-10 11:38:15 +00008755RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8756 HandleScope scope(isolate);
8757 ASSERT(args.length() >= 2);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008758 int argc = args.length() - 2;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008759 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8760 Object* receiver = args[0];
danno@chromium.orgc612e022011-11-10 11:38:15 +00008761
8762 // If there are too many arguments, allocate argv via malloc.
8763 const int argv_small_size = 10;
8764 Handle<Object> argv_small_buffer[argv_small_size];
8765 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8766 Handle<Object>* argv = argv_small_buffer;
8767 if (argc > argv_small_size) {
8768 argv = new Handle<Object>[argc];
8769 if (argv == NULL) return isolate->StackOverflow();
8770 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8771 }
8772
8773 for (int i = 0; i < argc; ++i) {
8774 MaybeObject* maybe = args[1 + i];
8775 Object* object;
8776 if (!maybe->To<Object>(&object)) return maybe;
8777 argv[i] = Handle<Object>(object);
8778 }
8779
8780 bool threw;
8781 Handle<JSReceiver> hfun(fun);
8782 Handle<Object> hreceiver(receiver);
8783 Handle<Object> result =
8784 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8785
8786 if (threw) return Failure::Exception();
8787 return *result;
8788}
8789
8790
lrn@chromium.org34e60782011-09-15 07:25:40 +00008791RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8792 HandleScope scope(isolate);
8793 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008794 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008795 Handle<Object> receiver = args.at<Object>(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008796 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008797 CONVERT_SMI_ARG_CHECKED(offset, 3);
8798 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008799 ASSERT(offset >= 0);
8800 ASSERT(argc >= 0);
8801
8802 // If there are too many arguments, allocate argv via malloc.
8803 const int argv_small_size = 10;
8804 Handle<Object> argv_small_buffer[argv_small_size];
8805 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8806 Handle<Object>* argv = argv_small_buffer;
8807 if (argc > argv_small_size) {
8808 argv = new Handle<Object>[argc];
8809 if (argv == NULL) return isolate->StackOverflow();
8810 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8811 }
8812
8813 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008814 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008815 }
8816
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008817 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008818 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008819 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008820
8821 if (threw) return Failure::Exception();
8822 return *result;
8823}
8824
8825
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008826RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008827 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008828 ASSERT(args.length() == 1);
8829 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8830 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8831}
8832
8833
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008834RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008835 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008836 ASSERT(args.length() == 1);
8837 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8838 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8839}
8840
8841
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008842RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008843 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008844 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008845
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008846 CONVERT_ARG_CHECKED(JSFunction, function, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008847 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008848 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008849 { MaybeObject* maybe_result =
8850 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008851 if (!maybe_result->ToObject(&result)) return maybe_result;
8852 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008853
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008854 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008855
kasper.lund7276f142008-07-30 08:49:36 +00008856 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008857}
8858
lrn@chromium.org303ada72010-10-27 09:33:13 +00008859
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008860RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8861 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008862 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008863 JSObject* extension_object;
8864 if (args[0]->IsJSObject()) {
8865 extension_object = JSObject::cast(args[0]);
8866 } else {
8867 // Convert the object to a proper JavaScript object.
8868 MaybeObject* maybe_js_object = args[0]->ToObject();
8869 if (!maybe_js_object->To(&extension_object)) {
8870 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8871 HandleScope scope(isolate);
8872 Handle<Object> handle = args.at<Object>(0);
8873 Handle<Object> result =
8874 isolate->factory()->NewTypeError("with_expression",
8875 HandleVector(&handle, 1));
8876 return isolate->Throw(*result);
8877 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008878 return maybe_js_object;
8879 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008880 }
8881 }
8882
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008883 JSFunction* function;
8884 if (args[1]->IsSmi()) {
8885 // A smi sentinel indicates a context nested inside global code rather
8886 // than some function. There is a canonical empty function that can be
8887 // gotten from the global context.
8888 function = isolate->context()->global_context()->closure();
8889 } else {
8890 function = JSFunction::cast(args[1]);
8891 }
8892
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008893 Context* context;
8894 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008895 isolate->heap()->AllocateWithContext(function,
8896 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008897 extension_object);
8898 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008899 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008900 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008901}
8902
8903
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008904RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008905 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008906 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008907 String* name = String::cast(args[0]);
8908 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008909 JSFunction* function;
8910 if (args[2]->IsSmi()) {
8911 // A smi sentinel indicates a context nested inside global code rather
8912 // than some function. There is a canonical empty function that can be
8913 // gotten from the global context.
8914 function = isolate->context()->global_context()->closure();
8915 } else {
8916 function = JSFunction::cast(args[2]);
8917 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008918 Context* context;
8919 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008920 isolate->heap()->AllocateCatchContext(function,
8921 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008922 name,
8923 thrown_object);
8924 if (!maybe_context->To(&context)) return maybe_context;
8925 isolate->set_context(context);
8926 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008927}
8928
8929
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008930RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8931 NoHandleAllocation ha;
8932 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008933 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008934 JSFunction* function;
8935 if (args[1]->IsSmi()) {
8936 // A smi sentinel indicates a context nested inside global code rather
8937 // than some function. There is a canonical empty function that can be
8938 // gotten from the global context.
8939 function = isolate->context()->global_context()->closure();
8940 } else {
8941 function = JSFunction::cast(args[1]);
8942 }
8943 Context* context;
8944 MaybeObject* maybe_context =
8945 isolate->heap()->AllocateBlockContext(function,
8946 isolate->context(),
8947 scope_info);
8948 if (!maybe_context->To(&context)) return maybe_context;
8949 isolate->set_context(context);
8950 return context;
8951}
8952
8953
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008954RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008955 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008956 ASSERT(args.length() == 2);
8957
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008958 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8959 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008960
8961 int index;
8962 PropertyAttributes attributes;
8963 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008964 BindingFlags binding_flags;
8965 Handle<Object> holder = context->Lookup(name,
8966 flags,
8967 &index,
8968 &attributes,
8969 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008970
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008971 // If the slot was not found the result is true.
8972 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008973 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008974 }
8975
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008976 // If the slot was found in a context, it should be DONT_DELETE.
8977 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008978 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008979 }
8980
8981 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008982 // the global object, or the subject of a with. Try to delete it
8983 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008984 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008985 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008986}
8987
8988
ager@chromium.orga1645e22009-09-09 19:27:10 +00008989// A mechanism to return a pair of Object pointers in registers (if possible).
8990// How this is achieved is calling convention-dependent.
8991// All currently supported x86 compiles uses calling conventions that are cdecl
8992// variants where a 64-bit value is returned in two 32-bit registers
8993// (edx:eax on ia32, r1:r0 on ARM).
8994// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8995// In Win64 calling convention, a struct of two pointers is returned in memory,
8996// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008997#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008998struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008999 MaybeObject* x;
9000 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009001};
ager@chromium.orga1645e22009-09-09 19:27:10 +00009002
lrn@chromium.org303ada72010-10-27 09:33:13 +00009003static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009004 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00009005 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
9006 // In Win64 they are assigned to a hidden first argument.
9007 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009008}
9009#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009010typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009011static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009012 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009013 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009014}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009015#endif
9016
9017
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009018static inline MaybeObject* Unhole(Heap* heap,
9019 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009020 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009021 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
9022 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009023 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009024}
9025
9026
danno@chromium.org40cb8782011-05-25 07:58:50 +00009027static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
9028 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009029 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009030 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009031 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009032 JSFunction* context_extension_function =
9033 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009034 // If the holder isn't a context extension object, we just return it
9035 // as the receiver. This allows arguments objects to be used as
9036 // receivers, but only if they are put in the context scope chain
9037 // explicitly via a with-statement.
9038 Object* constructor = holder->map()->constructor();
9039 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00009040 // Fall back to using the global object as the implicit receiver if
9041 // the property turns out to be a local variable allocated in a
9042 // context extension object - introduced via eval. Implicit global
9043 // receivers are indicated with the hole value.
9044 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009045}
9046
9047
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009048static ObjectPair LoadContextSlotHelper(Arguments args,
9049 Isolate* isolate,
9050 bool throw_error) {
9051 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00009052 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009053
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009054 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009055 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009056 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009057 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009058 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009059
9060 int index;
9061 PropertyAttributes attributes;
9062 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009063 BindingFlags binding_flags;
9064 Handle<Object> holder = context->Lookup(name,
9065 flags,
9066 &index,
9067 &attributes,
9068 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009069
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009070 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009071 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009072 ASSERT(holder->IsContext());
9073 // If the "property" we were looking for is a local variable, the
9074 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00009075 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009076 // Use the hole as the receiver to signal that the receiver is implicit
9077 // and that the global receiver should be used (as distinguished from an
9078 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00009079 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009080 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009081 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009082 switch (binding_flags) {
9083 case MUTABLE_CHECK_INITIALIZED:
9084 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9085 if (value->IsTheHole()) {
9086 Handle<Object> reference_error =
9087 isolate->factory()->NewReferenceError("not_defined",
9088 HandleVector(&name, 1));
9089 return MakePair(isolate->Throw(*reference_error), NULL);
9090 }
9091 // FALLTHROUGH
9092 case MUTABLE_IS_INITIALIZED:
9093 case IMMUTABLE_IS_INITIALIZED:
9094 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9095 ASSERT(!value->IsTheHole());
9096 return MakePair(value, *receiver);
9097 case IMMUTABLE_CHECK_INITIALIZED:
9098 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9099 case MISSING_BINDING:
9100 UNREACHABLE();
9101 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009102 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009103 }
9104
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009105 // Otherwise, if the slot was found the holder is a context extension
9106 // object, subject of a with, or a global object. We read the named
9107 // property from it.
9108 if (!holder.is_null()) {
9109 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9110 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009111 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009112 Handle<Object> receiver_handle(object->IsGlobalObject()
9113 ? GlobalObject::cast(*object)->global_receiver()
9114 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009115
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009116 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009117 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009118 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009119 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009120 }
9121
9122 if (throw_error) {
9123 // The property doesn't exist - throw exception.
9124 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009125 isolate->factory()->NewReferenceError("not_defined",
9126 HandleVector(&name, 1));
9127 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009128 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009129 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009130 return MakePair(isolate->heap()->undefined_value(),
9131 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009132 }
9133}
9134
9135
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009136RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009137 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009138}
9139
9140
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009141RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009142 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009143}
9144
9145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009146RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009147 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009148 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009149
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009150 Handle<Object> value(args[0], isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009151 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
9152 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009153 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9154 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
9155 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009156
9157 int index;
9158 PropertyAttributes attributes;
9159 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009160 BindingFlags binding_flags;
9161 Handle<Object> holder = context->Lookup(name,
9162 flags,
9163 &index,
9164 &attributes,
9165 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009166
9167 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009168 // The property was found in a context slot.
9169 Handle<Context> context = Handle<Context>::cast(holder);
9170 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9171 context->get(index)->IsTheHole()) {
9172 Handle<Object> error =
9173 isolate->factory()->NewReferenceError("not_defined",
9174 HandleVector(&name, 1));
9175 return isolate->Throw(*error);
9176 }
9177 // Ignore if read_only variable.
9178 if ((attributes & READ_ONLY) == 0) {
9179 // Context is a fixed array and set cannot fail.
9180 context->set(index, *value);
9181 } else if (strict_mode == kStrictMode) {
9182 // Setting read only property in strict mode.
9183 Handle<Object> error =
9184 isolate->factory()->NewTypeError("strict_cannot_assign",
9185 HandleVector(&name, 1));
9186 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009187 }
9188 return *value;
9189 }
9190
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009191 // Slow case: The property is not in a context slot. It is either in a
9192 // context extension object, a property of the subject of a with, or a
9193 // property of the global object.
9194 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009195
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009196 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009197 // The property exists on the holder.
9198 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009199 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009200 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009201 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009202
9203 if (strict_mode == kStrictMode) {
9204 // Throw in strict mode (assignment to undefined variable).
9205 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009206 isolate->factory()->NewReferenceError(
9207 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009208 return isolate->Throw(*error);
9209 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009210 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009211 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009212 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009213 }
9214
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009215 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009216 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009217 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009218 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009219 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009220 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009221 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009222 // Setting read only property in strict mode.
9223 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009224 isolate->factory()->NewTypeError(
9225 "strict_cannot_assign", HandleVector(&name, 1));
9226 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009227 }
9228 return *value;
9229}
9230
9231
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009232RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009233 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009234 ASSERT(args.length() == 1);
9235
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009236 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009237}
9238
9239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009240RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009241 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009242 ASSERT(args.length() == 1);
9243
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009244 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009245}
9246
9247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009248RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009249 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009250 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009251}
9252
9253
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009254RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009255 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009256 ASSERT(args.length() == 1);
9257
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009258 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009259 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009260 isolate->factory()->NewReferenceError("not_defined",
9261 HandleVector(&name, 1));
9262 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009263}
9264
9265
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009266RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009267 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009268
9269 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009270 if (isolate->stack_guard()->IsStackOverflow()) {
9271 NoHandleAllocation na;
9272 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009273 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009274
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009275 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009276}
9277
9278
yangguo@chromium.org56454712012-02-16 15:33:53 +00009279RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
9280 ASSERT(args.length() == 0);
9281 return Execution::HandleStackGuardInterrupt();
9282}
9283
9284
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009285static int StackSize() {
9286 int n = 0;
9287 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9288 return n;
9289}
9290
9291
9292static void PrintTransition(Object* result) {
9293 // indentation
9294 { const int nmax = 80;
9295 int n = StackSize();
9296 if (n <= nmax)
9297 PrintF("%4d:%*s", n, n, "");
9298 else
9299 PrintF("%4d:%*s", n, nmax, "...");
9300 }
9301
9302 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009303 JavaScriptFrame::PrintTop(stdout, true, false);
9304 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009305 } else {
9306 // function result
9307 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009308 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009309 PrintF("\n");
9310 }
9311}
9312
9313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009314RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009315 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009316 NoHandleAllocation ha;
9317 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009318 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009319}
9320
9321
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009322RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009323 NoHandleAllocation ha;
9324 PrintTransition(args[0]);
9325 return args[0]; // return TOS
9326}
9327
9328
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009329RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009330 NoHandleAllocation ha;
9331 ASSERT(args.length() == 1);
9332
9333#ifdef DEBUG
9334 if (args[0]->IsString()) {
9335 // If we have a string, assume it's a code "marker"
9336 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009337 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009338 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009339 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9340 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009341 } else {
9342 PrintF("DebugPrint: ");
9343 }
9344 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009345 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009346 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009347 HeapObject::cast(args[0])->map()->Print();
9348 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009349#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009350 // ShortPrint is available in release mode. Print is not.
9351 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009352#endif
9353 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009354 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009355
9356 return args[0]; // return TOS
9357}
9358
9359
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009360RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009361 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009362 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009363 isolate->PrintStack();
9364 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009365}
9366
9367
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009368RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009369 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009370 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009371
9372 // According to ECMA-262, section 15.9.1, page 117, the precision of
9373 // the number in a Date object representing a particular instant in
9374 // time is milliseconds. Therefore, we floor the result of getting
9375 // the OS time.
9376 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009377 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009378}
9379
9380
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009381RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009382 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009383 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009384
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009385 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009386 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009387
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009388 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009389
9390 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009391 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009392 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009393 RUNTIME_ASSERT(output->HasFastElements());
9394
9395 AssertNoAllocation no_allocation;
9396
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009397 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009398 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9399 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009400 String::FlatContent str_content = str->GetFlatContent();
9401 if (str_content.IsAscii()) {
9402 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009403 output_array,
9404 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009405 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009406 ASSERT(str_content.IsTwoByte());
9407 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009408 output_array,
9409 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009410 }
9411
9412 if (result) {
9413 return *output;
9414 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009415 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009416 }
9417}
9418
9419
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009420RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009421 NoHandleAllocation ha;
9422 ASSERT(args.length() == 1);
9423
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009424 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009425 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009426 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009427}
9428
9429
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009430RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009431 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009432 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009433
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009434 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009435}
9436
9437
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009438RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009439 NoHandleAllocation ha;
9440 ASSERT(args.length() == 1);
9441
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009442 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009443 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009444}
9445
9446
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009447RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009448 ASSERT(args.length() == 1);
9449 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009450 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009451 return JSGlobalObject::cast(global)->global_receiver();
9452}
9453
9454
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009455RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009456 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009457 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009458 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009459
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009460 source = Handle<String>(source->TryFlattenGetString());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009461 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009462 Handle<Object> result;
9463 if (source->IsSeqAsciiString()) {
9464 result = JsonParser<true>::Parse(source);
9465 } else {
9466 result = JsonParser<false>::Parse(source);
9467 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009468 if (result.is_null()) {
9469 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009470 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009471 return Failure::Exception();
9472 }
9473 return *result;
9474}
9475
9476
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009477bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9478 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009479 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9480 // Check with callback if set.
9481 AllowCodeGenerationFromStringsCallback callback =
9482 isolate->allow_code_gen_callback();
9483 if (callback == NULL) {
9484 // No callback set and code generation disallowed.
9485 return false;
9486 } else {
9487 // Callback set. Let it decide if code generation is allowed.
9488 VMState state(isolate, EXTERNAL);
9489 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009490 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009491}
9492
9493
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009494RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009495 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009496 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009497 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009498
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009499 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009500 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009501
9502 // Check if global context allows code generation from
9503 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009504 if (context->allow_code_gen_from_strings()->IsFalse() &&
9505 !CodeGenerationFromStringsAllowed(isolate, context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009506 return isolate->Throw(*isolate->factory()->NewError(
9507 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9508 }
9509
9510 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009511 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009512 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009513 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009514 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009515 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9516 context,
9517 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009518 return *fun;
9519}
9520
9521
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009522static ObjectPair CompileGlobalEval(Isolate* isolate,
9523 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009524 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009525 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009526 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009527 Handle<Context> context = Handle<Context>(isolate->context());
9528 Handle<Context> global_context = Handle<Context>(context->global_context());
9529
9530 // Check if global context allows code generation from
9531 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009532 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9533 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009534 isolate->Throw(*isolate->factory()->NewError(
9535 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9536 return MakePair(Failure::Exception(), NULL);
9537 }
9538
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009539 // Deal with a normal eval call with a string argument. Compile it
9540 // and return the compiled function bound in the local context.
9541 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9542 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009543 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009544 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009545 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009546 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009547 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009548 Handle<JSFunction> compiled =
9549 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009550 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009551 return MakePair(*compiled, *receiver);
9552}
9553
9554
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009555RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009556 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009557
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009558 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009559 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009560
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009561 // If "eval" didn't refer to the original GlobalEval, it's not a
9562 // direct call to eval.
9563 // (And even if it is, but the first argument isn't a string, just let
9564 // execution default to an indirect call to eval, which will also return
9565 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009566 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009567 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009568 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009569 }
9570
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009571 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009572 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009573 return CompileGlobalEval(isolate,
9574 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009575 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009576 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009577 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009578}
9579
9580
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009581RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009582 // This utility adjusts the property attributes for newly created Function
9583 // object ("new Function(...)") by changing the map.
9584 // All it does is changing the prototype property to enumerable
9585 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009586 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009587 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009588 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009589
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009590 Handle<Map> map = func->shared()->is_classic_mode()
9591 ? isolate->function_instance_map()
9592 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009593
9594 ASSERT(func->map()->instance_type() == map->instance_type());
9595 ASSERT(func->map()->instance_size() == map->instance_size());
9596 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009597 return *func;
9598}
9599
9600
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009601RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009602 // Allocate a block of memory in NewSpace (filled with a filler).
9603 // Use as fallback for allocation in generated code when NewSpace
9604 // is full.
9605 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009606 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009607 int size = size_smi->value();
9608 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9609 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009610 Heap* heap = isolate->heap();
9611 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009612 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009613 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009614 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009615 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009616 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009617 }
9618 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009619 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009620}
9621
9622
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009623// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009624// array. Returns true if the element was pushed on the stack and
9625// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009626RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009627 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009628 CONVERT_ARG_CHECKED(JSArray, array, 0);
9629 CONVERT_ARG_CHECKED(JSObject, element, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009630 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009631 int length = Smi::cast(array->length())->value();
9632 FixedArray* elements = FixedArray::cast(array->elements());
9633 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009634 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009635 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009636 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009637 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009638 { MaybeObject* maybe_obj =
9639 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009640 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9641 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009642 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009643}
9644
9645
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009646/**
9647 * A simple visitor visits every element of Array's.
9648 * The backend storage can be a fixed array for fast elements case,
9649 * or a dictionary for sparse array. Since Dictionary is a subtype
9650 * of FixedArray, the class can be used by both fast and slow cases.
9651 * The second parameter of the constructor, fast_elements, specifies
9652 * whether the storage is a FixedArray or Dictionary.
9653 *
9654 * An index limit is used to deal with the situation that a result array
9655 * length overflows 32-bit non-negative integer.
9656 */
9657class ArrayConcatVisitor {
9658 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009659 ArrayConcatVisitor(Isolate* isolate,
9660 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009661 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009662 isolate_(isolate),
9663 storage_(Handle<FixedArray>::cast(
9664 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009665 index_offset_(0u),
9666 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009667
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009668 ~ArrayConcatVisitor() {
9669 clear_storage();
9670 }
9671
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009672 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009673 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009674 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009675
9676 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009677 if (index < static_cast<uint32_t>(storage_->length())) {
9678 storage_->set(index, *elm);
9679 return;
9680 }
9681 // Our initial estimate of length was foiled, possibly by
9682 // getters on the arrays increasing the length of later arrays
9683 // during iteration.
9684 // This shouldn't happen in anything but pathological cases.
9685 SetDictionaryMode(index);
9686 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009687 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009688 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009689 Handle<SeededNumberDictionary> dict(
9690 SeededNumberDictionary::cast(*storage_));
9691 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009692 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009693 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009694 // Dictionary needed to grow.
9695 clear_storage();
9696 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009697 }
9698}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009699
9700 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009701 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9702 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009703 } else {
9704 index_offset_ += delta;
9705 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009706 }
9707
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009708 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009709 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009710 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009711 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009712 Handle<Map> map;
9713 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009714 map = isolate_->factory()->GetElementsTransitionMap(array,
9715 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009716 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009717 map = isolate_->factory()->GetElementsTransitionMap(array,
9718 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009719 }
9720 array->set_map(*map);
9721 array->set_length(*length);
9722 array->set_elements(*storage_);
9723 return array;
9724 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009725
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009726 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009727 // Convert storage to dictionary mode.
9728 void SetDictionaryMode(uint32_t index) {
9729 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009730 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009731 Handle<SeededNumberDictionary> slow_storage(
9732 isolate_->factory()->NewSeededNumberDictionary(
9733 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009734 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9735 for (uint32_t i = 0; i < current_length; i++) {
9736 HandleScope loop_scope;
9737 Handle<Object> element(current_storage->get(i));
9738 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009739 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009740 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009741 if (!new_storage.is_identical_to(slow_storage)) {
9742 slow_storage = loop_scope.CloseAndEscape(new_storage);
9743 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009744 }
9745 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009746 clear_storage();
9747 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009748 fast_elements_ = false;
9749 }
9750
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009751 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009752 isolate_->global_handles()->Destroy(
9753 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009754 }
9755
9756 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009757 storage_ = Handle<FixedArray>::cast(
9758 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009759 }
9760
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009761 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009762 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009763 // Index after last seen index. Always less than or equal to
9764 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009765 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009766 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009767};
9768
9769
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009770static uint32_t EstimateElementCount(Handle<JSArray> array) {
9771 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9772 int element_count = 0;
9773 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009774 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009775 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009776 // Fast elements can't have lengths that are not representable by
9777 // a 32-bit signed integer.
9778 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9779 int fast_length = static_cast<int>(length);
9780 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9781 for (int i = 0; i < fast_length; i++) {
9782 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009783 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009784 break;
9785 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009786 case FAST_DOUBLE_ELEMENTS:
9787 // TODO(1810): Decide if it's worthwhile to implement this.
9788 UNREACHABLE();
9789 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009790 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009791 Handle<SeededNumberDictionary> dictionary(
9792 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009793 int capacity = dictionary->Capacity();
9794 for (int i = 0; i < capacity; i++) {
9795 Handle<Object> key(dictionary->KeyAt(i));
9796 if (dictionary->IsKey(*key)) {
9797 element_count++;
9798 }
9799 }
9800 break;
9801 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009802 case NON_STRICT_ARGUMENTS_ELEMENTS:
9803 case EXTERNAL_BYTE_ELEMENTS:
9804 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9805 case EXTERNAL_SHORT_ELEMENTS:
9806 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9807 case EXTERNAL_INT_ELEMENTS:
9808 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9809 case EXTERNAL_FLOAT_ELEMENTS:
9810 case EXTERNAL_DOUBLE_ELEMENTS:
9811 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009812 // External arrays are always dense.
9813 return length;
9814 }
9815 // As an estimate, we assume that the prototype doesn't contain any
9816 // inherited elements.
9817 return element_count;
9818}
9819
9820
9821
9822template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009823static void IterateExternalArrayElements(Isolate* isolate,
9824 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009825 bool elements_are_ints,
9826 bool elements_are_guaranteed_smis,
9827 ArrayConcatVisitor* visitor) {
9828 Handle<ExternalArrayClass> array(
9829 ExternalArrayClass::cast(receiver->elements()));
9830 uint32_t len = static_cast<uint32_t>(array->length());
9831
9832 ASSERT(visitor != NULL);
9833 if (elements_are_ints) {
9834 if (elements_are_guaranteed_smis) {
9835 for (uint32_t j = 0; j < len; j++) {
9836 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009837 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009838 visitor->visit(j, e);
9839 }
9840 } else {
9841 for (uint32_t j = 0; j < len; j++) {
9842 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009843 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009844 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9845 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9846 visitor->visit(j, e);
9847 } else {
9848 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009849 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009850 visitor->visit(j, e);
9851 }
9852 }
9853 }
9854 } else {
9855 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009856 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009857 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009858 visitor->visit(j, e);
9859 }
9860 }
9861}
9862
9863
9864// Used for sorting indices in a List<uint32_t>.
9865static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9866 uint32_t a = *ap;
9867 uint32_t b = *bp;
9868 return (a == b) ? 0 : (a < b) ? -1 : 1;
9869}
9870
9871
9872static void CollectElementIndices(Handle<JSObject> object,
9873 uint32_t range,
9874 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009875 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009876 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009877 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009878 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009879 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9880 uint32_t length = static_cast<uint32_t>(elements->length());
9881 if (range < length) length = range;
9882 for (uint32_t i = 0; i < length; i++) {
9883 if (!elements->get(i)->IsTheHole()) {
9884 indices->Add(i);
9885 }
9886 }
9887 break;
9888 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009889 case FAST_DOUBLE_ELEMENTS: {
9890 // TODO(1810): Decide if it's worthwhile to implement this.
9891 UNREACHABLE();
9892 break;
9893 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009894 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009895 Handle<SeededNumberDictionary> dict(
9896 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009897 uint32_t capacity = dict->Capacity();
9898 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009899 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009900 Handle<Object> k(dict->KeyAt(j));
9901 if (dict->IsKey(*k)) {
9902 ASSERT(k->IsNumber());
9903 uint32_t index = static_cast<uint32_t>(k->Number());
9904 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009905 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009906 }
9907 }
9908 }
9909 break;
9910 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009911 default: {
9912 int dense_elements_length;
9913 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009914 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009915 dense_elements_length =
9916 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009917 break;
9918 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009919 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009920 dense_elements_length =
9921 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009922 break;
9923 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009924 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009925 dense_elements_length =
9926 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009927 break;
9928 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009929 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009930 dense_elements_length =
9931 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009932 break;
9933 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009934 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009935 dense_elements_length =
9936 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009937 break;
9938 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009939 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009940 dense_elements_length =
9941 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009942 break;
9943 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009944 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009945 dense_elements_length =
9946 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009947 break;
9948 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009949 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009950 dense_elements_length =
9951 ExternalFloatArray::cast(object->elements())->length();
9952 break;
9953 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009954 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009955 dense_elements_length =
9956 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009957 break;
9958 }
9959 default:
9960 UNREACHABLE();
9961 dense_elements_length = 0;
9962 break;
9963 }
9964 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9965 if (range <= length) {
9966 length = range;
9967 // We will add all indices, so we might as well clear it first
9968 // and avoid duplicates.
9969 indices->Clear();
9970 }
9971 for (uint32_t i = 0; i < length; i++) {
9972 indices->Add(i);
9973 }
9974 if (length == range) return; // All indices accounted for already.
9975 break;
9976 }
9977 }
9978
9979 Handle<Object> prototype(object->GetPrototype());
9980 if (prototype->IsJSObject()) {
9981 // The prototype will usually have no inherited element indices,
9982 // but we have to check.
9983 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9984 }
9985}
9986
9987
9988/**
9989 * A helper function that visits elements of a JSArray in numerical
9990 * order.
9991 *
9992 * The visitor argument called for each existing element in the array
9993 * with the element index and the element's value.
9994 * Afterwards it increments the base-index of the visitor by the array
9995 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009996 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009997 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009998static bool IterateElements(Isolate* isolate,
9999 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010000 ArrayConcatVisitor* visitor) {
10001 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
10002 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010003 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010004 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010005 // Run through the elements FixedArray and use HasElement and GetElement
10006 // to check the prototype for missing elements.
10007 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
10008 int fast_length = static_cast<int>(length);
10009 ASSERT(fast_length <= elements->length());
10010 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010011 HandleScope loop_scope(isolate);
10012 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010013 if (!element_value->IsTheHole()) {
10014 visitor->visit(j, element_value);
10015 } else if (receiver->HasElement(j)) {
10016 // Call GetElement on receiver, not its prototype, or getters won't
10017 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010018 element_value = Object::GetElement(receiver, j);
10019 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010020 visitor->visit(j, element_value);
10021 }
10022 }
10023 break;
10024 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010025 case FAST_DOUBLE_ELEMENTS: {
10026 // TODO(1810): Decide if it's worthwhile to implement this.
10027 UNREACHABLE();
10028 break;
10029 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010030 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010031 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010032 List<uint32_t> indices(dict->Capacity() / 2);
10033 // Collect all indices in the object and the prototypes less
10034 // than length. This might introduce duplicates in the indices list.
10035 CollectElementIndices(receiver, length, &indices);
10036 indices.Sort(&compareUInt32);
10037 int j = 0;
10038 int n = indices.length();
10039 while (j < n) {
10040 HandleScope loop_scope;
10041 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010042 Handle<Object> element = Object::GetElement(receiver, index);
10043 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010044 visitor->visit(index, element);
10045 // Skip to next different index (i.e., omit duplicates).
10046 do {
10047 j++;
10048 } while (j < n && indices[j] == index);
10049 }
10050 break;
10051 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010052 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010053 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
10054 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010055 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010056 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010057 visitor->visit(j, e);
10058 }
10059 break;
10060 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010061 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010062 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010063 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010064 break;
10065 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010066 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010067 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010068 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010069 break;
10070 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010071 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010072 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010073 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010074 break;
10075 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010076 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010077 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010078 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010079 break;
10080 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010081 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010082 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010083 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010084 break;
10085 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010086 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010087 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010088 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010089 break;
10090 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010091 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010092 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010093 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010094 break;
10095 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010096 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010097 IterateExternalArrayElements<ExternalDoubleArray, double>(
10098 isolate, receiver, false, false, visitor);
10099 break;
10100 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010101 default:
10102 UNREACHABLE();
10103 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010104 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010105 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010106 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010107}
10108
10109
10110/**
10111 * Array::concat implementation.
10112 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010113 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010114 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010115 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010116RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010117 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010118 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010119
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010120 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010121 int argument_count = static_cast<int>(arguments->length()->Number());
10122 RUNTIME_ASSERT(arguments->HasFastElements());
10123 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010124
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010125 // Pass 1: estimate the length and number of elements of the result.
10126 // The actual length can be larger if any of the arguments have getters
10127 // that mutate other arguments (but will otherwise be precise).
10128 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010129
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010130 uint32_t estimate_result_length = 0;
10131 uint32_t estimate_nof_elements = 0;
10132 {
10133 for (int i = 0; i < argument_count; i++) {
10134 HandleScope loop_scope;
10135 Handle<Object> obj(elements->get(i));
10136 uint32_t length_estimate;
10137 uint32_t element_estimate;
10138 if (obj->IsJSArray()) {
10139 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010140 // TODO(1810): Find out if it's worthwhile to properly support
10141 // arbitrary ElementsKinds. For now, pessimistically transition to
10142 // FAST_ELEMENTS.
10143 if (array->HasFastDoubleElements()) {
10144 array = Handle<JSArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010145 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010146 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010147 length_estimate =
10148 static_cast<uint32_t>(array->length()->Number());
10149 element_estimate =
10150 EstimateElementCount(array);
10151 } else {
10152 length_estimate = 1;
10153 element_estimate = 1;
10154 }
10155 // Avoid overflows by capping at kMaxElementCount.
10156 if (JSObject::kMaxElementCount - estimate_result_length <
10157 length_estimate) {
10158 estimate_result_length = JSObject::kMaxElementCount;
10159 } else {
10160 estimate_result_length += length_estimate;
10161 }
10162 if (JSObject::kMaxElementCount - estimate_nof_elements <
10163 element_estimate) {
10164 estimate_nof_elements = JSObject::kMaxElementCount;
10165 } else {
10166 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010167 }
10168 }
10169 }
10170
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010171 // If estimated number of elements is more than half of length, a
10172 // fixed array (fast case) is more time and space-efficient than a
10173 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010174 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010175
10176 Handle<FixedArray> storage;
10177 if (fast_case) {
10178 // The backing storage array must have non-existing elements to
10179 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010180 storage = isolate->factory()->NewFixedArrayWithHoles(
10181 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010182 } else {
10183 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10184 uint32_t at_least_space_for = estimate_nof_elements +
10185 (estimate_nof_elements >> 2);
10186 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010187 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010188 }
10189
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010190 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010191
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010192 for (int i = 0; i < argument_count; i++) {
10193 Handle<Object> obj(elements->get(i));
10194 if (obj->IsJSArray()) {
10195 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010196 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010197 return Failure::Exception();
10198 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010199 } else {
10200 visitor.visit(0, obj);
10201 visitor.increase_index_offset(1);
10202 }
10203 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010204
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010205 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010206}
10207
10208
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010209// This will not allocate (flatten the string), but it may run
10210// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010211RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010212 NoHandleAllocation ha;
10213 ASSERT(args.length() == 1);
10214
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010215 CONVERT_ARG_CHECKED(String, string, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010216 StringInputBuffer buffer(string);
10217 while (buffer.has_more()) {
10218 uint16_t character = buffer.GetNext();
10219 PrintF("%c", character);
10220 }
10221 return string;
10222}
10223
ager@chromium.org5ec48922009-05-05 07:25:34 +000010224// Moves all own elements of an object, that are below a limit, to positions
10225// starting at zero. All undefined values are placed after non-undefined values,
10226// and are followed by non-existing element. Does not change the length
10227// property.
10228// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010229RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010230 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010231 CONVERT_ARG_CHECKED(JSObject, object, 0);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010232 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10233 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010234}
10235
10236
10237// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010238RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010239 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010240 CONVERT_ARG_CHECKED(JSArray, from, 0);
10241 CONVERT_ARG_CHECKED(JSArray, to, 1);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010242 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010243 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010244 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010245 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10246 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010247 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010248 } else if (new_elements->map() ==
10249 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010250 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010251 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010252 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010253 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010254 maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010255 Object* new_map;
10256 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010257 to->set_map(Map::cast(new_map));
10258 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010259 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010260 Object* obj;
10261 { MaybeObject* maybe_obj = from->ResetElements();
10262 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10263 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010264 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010265 return to;
10266}
10267
10268
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010269// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010270RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010271 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010272 CONVERT_ARG_CHECKED(JSObject, object, 0);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010273 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010274 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010275 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
10276 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010277 } else if (object->IsJSArray()) {
10278 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010279 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010280 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010281 }
10282}
10283
10284
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010285RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010286 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010287
10288 ASSERT_EQ(3, args.length());
10289
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010290 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010291 Handle<Object> key1 = args.at<Object>(1);
10292 Handle<Object> key2 = args.at<Object>(2);
10293
10294 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010295 if (!key1->ToArrayIndex(&index1)
10296 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010297 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010298 }
10299
ager@chromium.orgac091b72010-05-05 07:34:42 +000010300 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010301 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010302 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010303 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010304 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010305
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010306 RETURN_IF_EMPTY_HANDLE(
10307 isolate, JSObject::SetElement(jsobject, index1, tmp2, kStrictMode));
10308 RETURN_IF_EMPTY_HANDLE(
10309 isolate, JSObject::SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010311 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010312}
10313
10314
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010315// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010316// might have elements. Can either return keys (positive integers) or
10317// intervals (pair of a negative integer (-start-1) followed by a
10318// positive (length)) or undefined values.
10319// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010320RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010321 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010322 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010323 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010324 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010325 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010326 // Create an array and get all the keys into it, then remove all the
10327 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010328 bool threw = false;
10329 Handle<FixedArray> keys =
10330 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10331 if (threw) return Failure::Exception();
10332
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010333 int keys_length = keys->length();
10334 for (int i = 0; i < keys_length; i++) {
10335 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010336 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010337 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010338 // Zap invalid keys.
10339 keys->set_undefined(i);
10340 }
10341 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010342 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010343 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010344 ASSERT(array->HasFastElements() ||
10345 array->HasFastSmiOnlyElements() ||
10346 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010347 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010348 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010349 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010350 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010351 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010352 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010353 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010354 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010355 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010356 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010357 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010358 }
10359}
10360
10361
10362// DefineAccessor takes an optional final argument which is the
ulan@chromium.org2efb9002012-01-19 15:36:35 +000010363// property attributes (e.g. DONT_ENUM, DONT_DELETE). IMPORTANT: due
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010364// to the way accessors are implemented, it is set for both the getter
10365// and setter on the first call to DefineAccessor and ignored on
10366// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010367RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010368 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10369 // Compute attributes.
10370 PropertyAttributes attributes = NONE;
10371 if (args.length() == 5) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010372 CONVERT_SMI_ARG_CHECKED(value, 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010373 // Only attribute bits should be set.
10374 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10375 attributes = static_cast<PropertyAttributes>(value);
10376 }
10377
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010378 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10379 CONVERT_ARG_CHECKED(String, name, 1);
10380 CONVERT_SMI_ARG_CHECKED(flag, 2);
10381 CONVERT_ARG_CHECKED(JSFunction, fun, 3);
10382 return obj->DefineAccessor(name, flag == 0, fun, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010383}
10384
10385
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010386RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010387 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010388 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10389 CONVERT_ARG_CHECKED(String, name, 1);
10390 CONVERT_SMI_ARG_CHECKED(flag, 2);
10391 return obj->LookupAccessor(name, flag == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010392}
10393
10394
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010395#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010396RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010397 ASSERT(args.length() == 0);
10398 return Execution::DebugBreakHelper();
10399}
10400
10401
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010402// Helper functions for wrapping and unwrapping stack frame ids.
10403static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010404 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010405 return Smi::FromInt(id >> 2);
10406}
10407
10408
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010409static StackFrame::Id UnwrapFrameId(int wrapped) {
10410 return static_cast<StackFrame::Id>(wrapped << 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010411}
10412
10413
10414// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010415// args[0]: debug event listener function to set or null or undefined for
10416// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010417// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010418RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010419 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010420 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10421 args[0]->IsUndefined() ||
10422 args[0]->IsNull());
10423 Handle<Object> callback = args.at<Object>(0);
10424 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010425 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010426
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010427 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010428}
10429
10430
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010431RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010432 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010433 isolate->stack_guard()->DebugBreak();
10434 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010435}
10436
10437
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010438static MaybeObject* DebugLookupResultValue(Heap* heap,
10439 Object* receiver,
10440 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010441 LookupResult* result,
10442 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010443 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010444 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010445 case NORMAL:
10446 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010447 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010448 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010449 }
10450 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010451 case FIELD:
10452 value =
10453 JSObject::cast(
10454 result->holder())->FastPropertyAt(result->GetFieldIndex());
10455 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010456 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010457 }
10458 return value;
10459 case CONSTANT_FUNCTION:
10460 return result->GetConstantFunction();
10461 case CALLBACKS: {
10462 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010463 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010464 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10465 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010466 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010467 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010468 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010469 maybe_value = heap->isolate()->pending_exception();
10470 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010471 if (caught_exception != NULL) {
10472 *caught_exception = true;
10473 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010474 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010475 }
10476 return value;
10477 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010478 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010479 }
10480 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010481 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010482 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010483 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010484 case CONSTANT_TRANSITION:
10485 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010486 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010487 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010488 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010489 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010490 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010491 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010492 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010493}
10494
10495
ager@chromium.org32912102009-01-16 10:38:43 +000010496// Get debugger related details for an object property.
10497// args[0]: object holding property
10498// args[1]: name of the property
10499//
10500// The array returned contains the following information:
10501// 0: Property value
10502// 1: Property details
10503// 2: Property value is exception
10504// 3: Getter function if defined
10505// 4: Setter function if defined
10506// Items 2-4 are only filled if the property has either a getter or a setter
10507// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010508RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010509 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010510
10511 ASSERT(args.length() == 2);
10512
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010513 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10514 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010515
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010516 // Make sure to set the current context to the context before the debugger was
10517 // entered (if the debugger is entered). The reason for switching context here
10518 // is that for some property lookups (accessors and interceptors) callbacks
10519 // into the embedding application can occour, and the embedding application
10520 // could have the assumption that its own global context is the current
10521 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010522 SaveContext save(isolate);
10523 if (isolate->debug()->InDebugger()) {
10524 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010525 }
10526
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010527 // Skip the global proxy as it has no properties and always delegates to the
10528 // real global object.
10529 if (obj->IsJSGlobalProxy()) {
10530 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10531 }
10532
10533
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010534 // Check if the name is trivially convertible to an index and get the element
10535 // if so.
10536 uint32_t index;
10537 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010538 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010539 Object* element_or_char;
10540 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010541 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010542 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10543 return maybe_element_or_char;
10544 }
10545 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010546 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010547 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010548 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010549 }
10550
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010551 // Find the number of objects making up this.
10552 int length = LocalPrototypeChainLength(*obj);
10553
10554 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010555 Handle<JSObject> jsproto = obj;
10556 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010557 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010558 jsproto->LocalLookup(*name, &result);
10559 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010560 // LookupResult is not GC safe as it holds raw object pointers.
10561 // GC can happen later in this code so put the required fields into
10562 // local variables using handles when required for later use.
10563 PropertyType result_type = result.type();
10564 Handle<Object> result_callback_obj;
10565 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010566 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10567 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010568 }
10569 Smi* property_details = result.GetPropertyDetails().AsSmi();
10570 // DebugLookupResultValue can cause GC so details from LookupResult needs
10571 // to be copied to handles before this.
10572 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010573 Object* raw_value;
10574 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010575 DebugLookupResultValue(isolate->heap(), *obj, *name,
10576 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010577 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10578 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010579 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010580
10581 // If the callback object is a fixed array then it contains JavaScript
10582 // getter and/or setter.
10583 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010584 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010585 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010586 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010587 details->set(0, *value);
10588 details->set(1, property_details);
10589 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010590 details->set(2, isolate->heap()->ToBoolean(caught_exception));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010591 details->set(3, AccessorPair::cast(*result_callback_obj)->getter());
10592 details->set(4, AccessorPair::cast(*result_callback_obj)->setter());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010593 }
10594
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010595 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010596 }
10597 if (i < length - 1) {
10598 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10599 }
10600 }
10601
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010602 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010603}
10604
10605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010606RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010607 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010608
10609 ASSERT(args.length() == 2);
10610
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010611 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10612 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010613
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010614 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010615 obj->Lookup(*name, &result);
10616 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010617 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010618 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010619 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010620}
10621
10622
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010623// Return the property type calculated from the property details.
10624// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010625RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010626 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010627 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10628 return Smi::FromInt(static_cast<int>(details.type()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010629}
10630
10631
10632// Return the property attribute calculated from the property details.
10633// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010634RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010635 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010636 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10637 return Smi::FromInt(static_cast<int>(details.attributes()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010638}
10639
10640
10641// Return the property insertion index calculated from the property details.
10642// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010643RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010644 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010645 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10646 return Smi::FromInt(details.index());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010647}
10648
10649
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010650// Return property value from named interceptor.
10651// args[0]: object
10652// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010653RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010654 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010655 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010656 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010657 RUNTIME_ASSERT(obj->HasNamedInterceptor());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010658 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010659
10660 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010661 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010662}
10663
10664
10665// Return element value from indexed interceptor.
10666// args[0]: object
10667// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010668RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010669 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010670 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010671 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010672 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10673 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10674
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010675 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010676}
10677
10678
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010679RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010680 ASSERT(args.length() >= 1);
10681 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010682 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010683 if (isolate->debug()->break_id() == 0 ||
10684 break_id != isolate->debug()->break_id()) {
10685 return isolate->Throw(
10686 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010687 }
10688
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010689 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010690}
10691
10692
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010693RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010694 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010695 ASSERT(args.length() == 1);
10696
10697 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010698 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010699 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10700 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010701 if (!maybe_result->ToObject(&result)) return maybe_result;
10702 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010703
10704 // Count all frames which are relevant to debugging stack trace.
10705 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010706 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010707 if (id == StackFrame::NO_ID) {
10708 // If there is no JavaScript stack frame count is 0.
10709 return Smi::FromInt(0);
10710 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010711
10712 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10713 n += it.frame()->GetInlineCount();
10714 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010715 return Smi::FromInt(n);
10716}
10717
10718
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010719class FrameInspector {
10720 public:
10721 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010722 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010723 Isolate* isolate)
10724 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10725 // Calculate the deoptimized frame.
10726 if (frame->is_optimized()) {
10727 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010728 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010729 }
10730 has_adapted_arguments_ = frame_->has_adapted_arguments();
10731 is_optimized_ = frame_->is_optimized();
10732 }
10733
10734 ~FrameInspector() {
10735 // Get rid of the calculated deoptimized frame if any.
10736 if (deoptimized_frame_ != NULL) {
10737 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10738 isolate_);
10739 }
10740 }
10741
10742 int GetParametersCount() {
10743 return is_optimized_
10744 ? deoptimized_frame_->parameters_count()
10745 : frame_->ComputeParametersCount();
10746 }
10747 int expression_count() { return deoptimized_frame_->expression_count(); }
10748 Object* GetFunction() {
10749 return is_optimized_
10750 ? deoptimized_frame_->GetFunction()
10751 : frame_->function();
10752 }
10753 Object* GetParameter(int index) {
10754 return is_optimized_
10755 ? deoptimized_frame_->GetParameter(index)
10756 : frame_->GetParameter(index);
10757 }
10758 Object* GetExpression(int index) {
10759 return is_optimized_
10760 ? deoptimized_frame_->GetExpression(index)
10761 : frame_->GetExpression(index);
10762 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010763 int GetSourcePosition() {
10764 return is_optimized_
10765 ? deoptimized_frame_->GetSourcePosition()
10766 : frame_->LookupCode()->SourcePosition(frame_->pc());
10767 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010768
10769 // To inspect all the provided arguments the frame might need to be
10770 // replaced with the arguments frame.
10771 void SetArgumentsFrame(JavaScriptFrame* frame) {
10772 ASSERT(has_adapted_arguments_);
10773 frame_ = frame;
10774 is_optimized_ = frame_->is_optimized();
10775 ASSERT(!is_optimized_);
10776 }
10777
10778 private:
10779 JavaScriptFrame* frame_;
10780 DeoptimizedFrameInfo* deoptimized_frame_;
10781 Isolate* isolate_;
10782 bool is_optimized_;
10783 bool has_adapted_arguments_;
10784
10785 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10786};
10787
10788
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010789static const int kFrameDetailsFrameIdIndex = 0;
10790static const int kFrameDetailsReceiverIndex = 1;
10791static const int kFrameDetailsFunctionIndex = 2;
10792static const int kFrameDetailsArgumentCountIndex = 3;
10793static const int kFrameDetailsLocalCountIndex = 4;
10794static const int kFrameDetailsSourcePositionIndex = 5;
10795static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010796static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010797static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010798static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010799
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010800
10801static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10802 JavaScriptFrame* frame) {
10803 SaveContext* save = isolate->save_context();
10804 while (save != NULL && !save->IsBelowFrame(frame)) {
10805 save = save->prev();
10806 }
10807 ASSERT(save != NULL);
10808 return save;
10809}
10810
10811
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010812// Return an array with frame details
10813// args[0]: number: break id
10814// args[1]: number: frame index
10815//
10816// The array returned contains the following information:
10817// 0: Frame id
10818// 1: Receiver
10819// 2: Function
10820// 3: Argument count
10821// 4: Local count
10822// 5: Source position
10823// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010824// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010825// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010826// Arguments name, value
10827// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010828// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010829RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010830 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010831 ASSERT(args.length() == 2);
10832
10833 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010834 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010835 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10836 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010837 if (!maybe_check->ToObject(&check)) return maybe_check;
10838 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010839 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010840 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010841
10842 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010843 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010844 if (id == StackFrame::NO_ID) {
10845 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010846 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010847 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010848
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010849 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010850 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010851 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010852 if (index < count + it.frame()->GetInlineCount()) break;
10853 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010854 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010855 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010856
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010857 bool is_optimized = it.frame()->is_optimized();
10858
10859 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10860 if (is_optimized) {
10861 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010862 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010863 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010864 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010865
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010866 // Traverse the saved contexts chain to find the active context for the
10867 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010868 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010869
10870 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010871 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010872
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010873 // Find source position in unoptimized code.
10874 int position = frame_inspector.GetSourcePosition();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010875
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010876 // Check for constructor frame. Inlined frames cannot be construct calls.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010877 bool inlined_frame = is_optimized && inlined_jsframe_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010878 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010879
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010880 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010881 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010882 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010883 Handle<ScopeInfo> scope_info(shared->scope_info());
10884 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010885
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010886 // Get the locals names and values into a temporary array.
10887 //
10888 // TODO(1240907): Hide compiler-introduced stack variables
10889 // (e.g. .result)? For users of the debugger, they will probably be
10890 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010891 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010892 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010893
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010894 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010895 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010896 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010897 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010898 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010899 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010900 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010901 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010902 // Get the context containing declarations.
10903 Handle<Context> context(
10904 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010905 for (; i < scope_info->LocalCount(); ++i) {
10906 Handle<String> name(scope_info->LocalName(i));
10907 VariableMode mode;
10908 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010909 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010910 locals->set(i * 2 + 1, context->get(
10911 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010912 }
10913 }
10914
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010915 // Check whether this frame is positioned at return. If not top
10916 // frame or if the frame is optimized it cannot be at a return.
10917 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010918 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010919 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010920 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010921
10922 // If positioned just before return find the value to be returned and add it
10923 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010924 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010925 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010926 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010927 Address internal_frame_sp = NULL;
10928 while (!it2.done()) {
10929 if (it2.frame()->is_internal()) {
10930 internal_frame_sp = it2.frame()->sp();
10931 } else {
10932 if (it2.frame()->is_java_script()) {
10933 if (it2.frame()->id() == it.frame()->id()) {
10934 // The internal frame just before the JavaScript frame contains the
10935 // value to return on top. A debug break at return will create an
10936 // internal frame to store the return value (eax/rax/r0) before
10937 // entering the debug break exit frame.
10938 if (internal_frame_sp != NULL) {
10939 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010940 Handle<Object>(Memory::Object_at(internal_frame_sp),
10941 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010942 break;
10943 }
10944 }
10945 }
10946
10947 // Indicate that the previous frame was not an internal frame.
10948 internal_frame_sp = NULL;
10949 }
10950 it2.Advance();
10951 }
10952 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010953
10954 // Now advance to the arguments adapter frame (if any). It contains all
10955 // the provided parameters whereas the function frame always have the number
10956 // of arguments matching the functions parameters. The rest of the
10957 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010958 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010959 it.AdvanceToArgumentsFrame();
10960 frame_inspector.SetArgumentsFrame(it.frame());
10961 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010962
10963 // Find the number of arguments to fill. At least fill the number of
10964 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010965 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010966 if (argument_count < frame_inspector.GetParametersCount()) {
10967 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010968 }
10969
10970 // Calculate the size of the result.
10971 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010972 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010973 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010974 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010975
10976 // Add the frame id.
10977 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10978
10979 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010980 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010981
10982 // Add the arguments count.
10983 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10984
10985 // Add the locals count
10986 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010987 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010988
10989 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010990 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010991 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10992 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010993 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010994 }
10995
10996 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010997 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010998
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010999 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011000 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011001
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011002 // Add flags to indicate information on whether this frame is
11003 // bit 0: invoked in the debugger context.
11004 // bit 1: optimized frame.
11005 // bit 2: inlined in optimized frame
11006 int flags = 0;
11007 if (*save->context() == *isolate->debug()->debug_context()) {
11008 flags |= 1 << 0;
11009 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011010 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011011 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011012 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011013 }
11014 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011015
11016 // Fill the dynamic part.
11017 int details_index = kFrameDetailsFirstDynamicIndex;
11018
11019 // Add arguments name and value.
11020 for (int i = 0; i < argument_count; i++) {
11021 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011022 if (i < scope_info->ParameterCount()) {
11023 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011024 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011025 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011026 }
11027
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011028 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011029 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011030 // Get the value from the stack.
11031 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011032 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011033 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011034 }
11035 }
11036
11037 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011038 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011039 details->set(details_index++, locals->get(i));
11040 }
11041
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011042 // Add the value being returned.
11043 if (at_return) {
11044 details->set(details_index++, *return_value);
11045 }
11046
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011047 // Add the receiver (same as in function frame).
11048 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
11049 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011050 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011051 if (!receiver->IsJSObject() &&
11052 shared->is_classic_mode() &&
11053 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000011054 // If the receiver is not a JSObject and the function is not a
11055 // builtin or strict-mode we have hit an optimization where a
11056 // value object is not converted into a wrapped JS objects. To
11057 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011058 // by creating correct wrapper object based on the calling frame's
11059 // global context.
11060 it.Advance();
11061 Handle<Context> calling_frames_global_context(
11062 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011063 receiver =
11064 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011065 }
11066 details->set(kFrameDetailsReceiverIndex, *receiver);
11067
11068 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011069 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011070}
11071
11072
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011073// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011074static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011075 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011076 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011077 Handle<Context> context,
11078 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011079 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011080 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11081 VariableMode mode;
11082 InitializationFlag init_flag;
11083 int context_index = scope_info->ContextSlotIndex(
11084 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011085
whesse@chromium.org7b260152011-06-20 15:33:18 +000011086 RETURN_IF_EMPTY_HANDLE_VALUE(
11087 isolate,
11088 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011089 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000011090 Handle<Object>(context->get(context_index), isolate),
11091 NONE,
11092 kNonStrictMode),
11093 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011094 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011095
11096 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011097}
11098
11099
11100// Create a plain JSObject which materializes the local scope for the specified
11101// frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011102static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011103 Isolate* isolate,
11104 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011105 FrameInspector* frame_inspector) {
11106 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011107 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011108 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011109
11110 // Allocate and initialize a JSObject with all the arguments, stack locals
11111 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011112 Handle<JSObject> local_scope =
11113 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011114
11115 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011116 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011117 Handle<Object> value(
11118 i < frame_inspector->GetParametersCount() ?
11119 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value());
11120
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011121 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011122 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011123 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011124 Handle<String>(scope_info->ParameterName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011125 value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011126 NONE,
11127 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011128 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011129 }
11130
11131 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011132 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011133 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011134 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011135 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011136 Handle<String>(scope_info->StackLocalName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011137 Handle<Object>(frame_inspector->GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011138 NONE,
11139 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011140 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011141 }
11142
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011143 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011144 // Third fill all context locals.
11145 Handle<Context> frame_context(Context::cast(frame->context()));
11146 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011147 if (!CopyContextLocalsToScopeObject(
11148 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011149 return Handle<JSObject>();
11150 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011151
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011152 // Finally copy any properties from the function context extension.
11153 // These will be variables introduced by eval.
11154 if (function_context->closure() == *function) {
11155 if (function_context->has_extension() &&
11156 !function_context->IsGlobalContext()) {
11157 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011158 bool threw = false;
11159 Handle<FixedArray> keys =
11160 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11161 if (threw) return Handle<JSObject>();
11162
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011163 for (int i = 0; i < keys->length(); i++) {
11164 // Names of variables introduced by eval are strings.
11165 ASSERT(keys->get(i)->IsString());
11166 Handle<String> key(String::cast(keys->get(i)));
11167 RETURN_IF_EMPTY_HANDLE_VALUE(
11168 isolate,
11169 SetProperty(local_scope,
11170 key,
11171 GetProperty(ext, key),
11172 NONE,
11173 kNonStrictMode),
11174 Handle<JSObject>());
11175 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011176 }
11177 }
11178 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011179
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011180 return local_scope;
11181}
11182
11183
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011184static Handle<JSObject> MaterializeLocalScope(
11185 Isolate* isolate,
11186 JavaScriptFrame* frame,
11187 int inlined_jsframe_index) {
11188 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11189 return MaterializeLocalScopeWithFrameInspector(isolate,
11190 frame,
11191 &frame_inspector);
11192}
11193
11194
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011195// Create a plain JSObject which materializes the closure content for the
11196// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011197static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11198 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011199 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011200
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011201 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011202 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011203
ulan@chromium.org2efb9002012-01-19 15:36:35 +000011204 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011205 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011206 Handle<JSObject> closure_scope =
11207 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011208
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011209 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011210 if (!CopyContextLocalsToScopeObject(
11211 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011212 return Handle<JSObject>();
11213 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011214
11215 // Finally copy any properties from the function context extension. This will
11216 // be variables introduced by eval.
11217 if (context->has_extension()) {
11218 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011219 bool threw = false;
11220 Handle<FixedArray> keys =
11221 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11222 if (threw) return Handle<JSObject>();
11223
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011224 for (int i = 0; i < keys->length(); i++) {
11225 // Names of variables introduced by eval are strings.
11226 ASSERT(keys->get(i)->IsString());
11227 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011228 RETURN_IF_EMPTY_HANDLE_VALUE(
11229 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011230 SetProperty(closure_scope,
11231 key,
11232 GetProperty(ext, key),
11233 NONE,
11234 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011235 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011236 }
11237 }
11238
11239 return closure_scope;
11240}
11241
11242
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011243// Create a plain JSObject which materializes the scope for the specified
11244// catch context.
11245static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11246 Handle<Context> context) {
11247 ASSERT(context->IsCatchContext());
11248 Handle<String> name(String::cast(context->extension()));
11249 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11250 Handle<JSObject> catch_scope =
11251 isolate->factory()->NewJSObject(isolate->object_function());
11252 RETURN_IF_EMPTY_HANDLE_VALUE(
11253 isolate,
11254 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11255 Handle<JSObject>());
11256 return catch_scope;
11257}
11258
11259
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011260// Create a plain JSObject which materializes the block scope for the specified
11261// block context.
11262static Handle<JSObject> MaterializeBlockScope(
11263 Isolate* isolate,
11264 Handle<Context> context) {
11265 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011266 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011267
11268 // Allocate and initialize a JSObject with all the arguments, stack locals
11269 // heap locals and extension properties of the debugged function.
11270 Handle<JSObject> block_scope =
11271 isolate->factory()->NewJSObject(isolate->object_function());
11272
11273 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011274 if (!CopyContextLocalsToScopeObject(
11275 isolate, scope_info, context, block_scope)) {
11276 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011277 }
11278
11279 return block_scope;
11280}
11281
11282
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011283// Create a plain JSObject which materializes the module scope for the specified
11284// module context.
11285static Handle<JSObject> MaterializeModuleScope(
11286 Isolate* isolate,
11287 Handle<Context> context) {
11288 ASSERT(context->IsModuleContext());
11289 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
11290
11291 // Allocate and initialize a JSObject with all the members of the debugged
11292 // module.
11293 Handle<JSObject> module_scope =
11294 isolate->factory()->NewJSObject(isolate->object_function());
11295
11296 // Fill all context locals.
11297 if (!CopyContextLocalsToScopeObject(
11298 isolate, scope_info, context, module_scope)) {
11299 return Handle<JSObject>();
11300 }
11301
11302 return module_scope;
11303}
11304
11305
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011306// Iterate over the actual scopes visible from a stack frame. The iteration
11307// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011308// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011309// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011310class ScopeIterator {
11311 public:
11312 enum ScopeType {
11313 ScopeTypeGlobal = 0,
11314 ScopeTypeLocal,
11315 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011316 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011317 ScopeTypeCatch,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011318 ScopeTypeBlock,
11319 ScopeTypeModule
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011320 };
11321
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011322 ScopeIterator(Isolate* isolate,
11323 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011324 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011325 : isolate_(isolate),
11326 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011327 inlined_jsframe_index_(inlined_jsframe_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011328 function_(JSFunction::cast(frame->function())),
11329 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011330 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011331
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011332 // Catch the case when the debugger stops in an internal function.
11333 Handle<SharedFunctionInfo> shared_info(function_->shared());
11334 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11335 if (shared_info->script() == isolate->heap()->undefined_value()) {
11336 while (context_->closure() == *function_) {
11337 context_ = Handle<Context>(context_->previous(), isolate_);
11338 }
11339 return;
11340 }
11341
11342 // Get the debug info (create it if it does not exist).
11343 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
11344 // Return if ensuring debug info failed.
11345 return;
11346 }
11347 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11348
11349 // Find the break point where execution has stopped.
11350 BreakLocationIterator break_location_iterator(debug_info,
11351 ALL_BREAK_LOCATIONS);
11352 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
11353 if (break_location_iterator.IsExit()) {
11354 // We are within the return sequence. At the momemt it is not possible to
11355 // get a source position which is consistent with the current scope chain.
11356 // Thus all nested with, catch and block contexts are skipped and we only
11357 // provide the function scope.
11358 if (scope_info->HasContext()) {
11359 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11360 } else {
11361 while (context_->closure() == *function_) {
11362 context_ = Handle<Context>(context_->previous(), isolate_);
11363 }
11364 }
11365 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
11366 } else {
11367 // Reparse the code and analyze the scopes.
11368 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11369 Handle<Script> script(Script::cast(shared_info->script()));
11370 Scope* scope = NULL;
11371
11372 // Check whether we are in global, eval or function code.
11373 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11374 if (scope_info->Type() != FUNCTION_SCOPE) {
11375 // Global or eval code.
11376 CompilationInfo info(script);
11377 if (scope_info->Type() == GLOBAL_SCOPE) {
11378 info.MarkAsGlobal();
11379 } else {
11380 ASSERT(scope_info->Type() == EVAL_SCOPE);
11381 info.MarkAsEval();
11382 info.SetCallingContext(Handle<Context>(function_->context()));
11383 }
11384 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11385 scope = info.function()->scope();
11386 }
11387 } else {
11388 // Function code
11389 CompilationInfo info(shared_info);
11390 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11391 scope = info.function()->scope();
11392 }
11393 }
11394
11395 // Retrieve the scope chain for the current position.
11396 if (scope != NULL) {
11397 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11398 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11399 } else {
11400 // A failed reparse indicates that the preparser has diverged from the
11401 // parser or that the preparse data given to the initial parse has been
11402 // faulty. We fail in debug mode but in release mode we only provide the
11403 // information we get from the context chain but nothing about
11404 // completely stack allocated scopes or stack allocated locals.
11405 UNREACHABLE();
11406 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011407 }
11408 }
11409
11410 // More scopes?
11411 bool Done() { return context_.is_null(); }
11412
11413 // Move to the next scope.
11414 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011415 ScopeType scope_type = Type();
11416 if (scope_type == ScopeTypeGlobal) {
11417 // The global scope is always the last in the chain.
11418 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011419 context_ = Handle<Context>();
11420 return;
11421 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011422 if (nested_scope_chain_.is_empty()) {
11423 context_ = Handle<Context>(context_->previous(), isolate_);
11424 } else {
11425 if (nested_scope_chain_.last()->HasContext()) {
11426 ASSERT(context_->previous() != NULL);
11427 context_ = Handle<Context>(context_->previous(), isolate_);
11428 }
11429 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011430 }
11431 }
11432
11433 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011434 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011435 if (!nested_scope_chain_.is_empty()) {
11436 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11437 switch (scope_info->Type()) {
11438 case FUNCTION_SCOPE:
11439 ASSERT(context_->IsFunctionContext() ||
11440 !scope_info->HasContext());
11441 return ScopeTypeLocal;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011442 case MODULE_SCOPE:
11443 ASSERT(context_->IsModuleContext());
11444 return ScopeTypeModule;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011445 case GLOBAL_SCOPE:
11446 ASSERT(context_->IsGlobalContext());
11447 return ScopeTypeGlobal;
11448 case WITH_SCOPE:
11449 ASSERT(context_->IsWithContext());
11450 return ScopeTypeWith;
11451 case CATCH_SCOPE:
11452 ASSERT(context_->IsCatchContext());
11453 return ScopeTypeCatch;
11454 case BLOCK_SCOPE:
11455 ASSERT(!scope_info->HasContext() ||
11456 context_->IsBlockContext());
11457 return ScopeTypeBlock;
11458 case EVAL_SCOPE:
11459 UNREACHABLE();
11460 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011461 }
11462 if (context_->IsGlobalContext()) {
11463 ASSERT(context_->global()->IsGlobalObject());
11464 return ScopeTypeGlobal;
11465 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011466 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011467 return ScopeTypeClosure;
11468 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011469 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011470 return ScopeTypeCatch;
11471 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011472 if (context_->IsBlockContext()) {
11473 return ScopeTypeBlock;
11474 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011475 if (context_->IsModuleContext()) {
11476 return ScopeTypeModule;
11477 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011478 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011479 return ScopeTypeWith;
11480 }
11481
11482 // Return the JavaScript object with the content of the current scope.
11483 Handle<JSObject> ScopeObject() {
11484 switch (Type()) {
11485 case ScopeIterator::ScopeTypeGlobal:
11486 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011487 case ScopeIterator::ScopeTypeLocal:
11488 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011489 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011490 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011491 case ScopeIterator::ScopeTypeWith:
11492 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011493 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11494 case ScopeIterator::ScopeTypeCatch:
11495 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011496 case ScopeIterator::ScopeTypeClosure:
11497 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011498 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011499 case ScopeIterator::ScopeTypeBlock:
11500 return MaterializeBlockScope(isolate_, CurrentContext());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011501 case ScopeIterator::ScopeTypeModule:
11502 return MaterializeModuleScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011503 }
11504 UNREACHABLE();
11505 return Handle<JSObject>();
11506 }
11507
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011508 Handle<ScopeInfo> CurrentScopeInfo() {
11509 if (!nested_scope_chain_.is_empty()) {
11510 return nested_scope_chain_.last();
11511 } else if (context_->IsBlockContext()) {
11512 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11513 } else if (context_->IsFunctionContext()) {
11514 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11515 }
11516 return Handle<ScopeInfo>::null();
11517 }
11518
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011519 // Return the context for this scope. For the local context there might not
11520 // be an actual context.
11521 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011522 if (Type() == ScopeTypeGlobal ||
11523 nested_scope_chain_.is_empty()) {
11524 return context_;
11525 } else if (nested_scope_chain_.last()->HasContext()) {
11526 return context_;
11527 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011528 return Handle<Context>();
11529 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011530 }
11531
11532#ifdef DEBUG
11533 // Debug print of the content of the current scope.
11534 void DebugPrint() {
11535 switch (Type()) {
11536 case ScopeIterator::ScopeTypeGlobal:
11537 PrintF("Global:\n");
11538 CurrentContext()->Print();
11539 break;
11540
11541 case ScopeIterator::ScopeTypeLocal: {
11542 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011543 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011544 if (!CurrentContext().is_null()) {
11545 CurrentContext()->Print();
11546 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011547 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011548 if (extension->IsJSContextExtensionObject()) {
11549 extension->Print();
11550 }
11551 }
11552 }
11553 break;
11554 }
11555
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011556 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011557 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011558 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011559 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011560
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011561 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011562 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011563 CurrentContext()->extension()->Print();
11564 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011565 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011566
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011567 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011568 PrintF("Closure:\n");
11569 CurrentContext()->Print();
11570 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011571 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011572 if (extension->IsJSContextExtensionObject()) {
11573 extension->Print();
11574 }
11575 }
11576 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011577
11578 default:
11579 UNREACHABLE();
11580 }
11581 PrintF("\n");
11582 }
11583#endif
11584
11585 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011586 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011587 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011588 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011589 Handle<JSFunction> function_;
11590 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011591 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011592
11593 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11594};
11595
11596
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011597RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011598 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011599 ASSERT(args.length() == 2);
11600
11601 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011602 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011603 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11604 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011605 if (!maybe_check->ToObject(&check)) return maybe_check;
11606 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011607 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011608
11609 // Get the frame where the debugging is performed.
11610 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011611 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011612 JavaScriptFrame* frame = it.frame();
11613
11614 // Count the visible scopes.
11615 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011616 for (ScopeIterator it(isolate, frame, 0);
11617 !it.Done();
11618 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011619 n++;
11620 }
11621
11622 return Smi::FromInt(n);
11623}
11624
11625
11626static const int kScopeDetailsTypeIndex = 0;
11627static const int kScopeDetailsObjectIndex = 1;
11628static const int kScopeDetailsSize = 2;
11629
11630// Return an array with scope details
11631// args[0]: number: break id
11632// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011633// args[2]: number: inlined frame index
11634// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011635//
11636// The array returned contains the following information:
11637// 0: Scope type
11638// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011639RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011640 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011641 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011642
11643 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011644 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011645 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11646 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011647 if (!maybe_check->ToObject(&check)) return maybe_check;
11648 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011649 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011650 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011651 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011652
11653 // Get the frame where the debugging is performed.
11654 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011655 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011656 JavaScriptFrame* frame = frame_it.frame();
11657
11658 // Find the requested scope.
11659 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011660 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011661 for (; !it.Done() && n < index; it.Next()) {
11662 n++;
11663 }
11664 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011665 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011666 }
11667
11668 // Calculate the size of the result.
11669 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011670 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011671
11672 // Fill in scope details.
11673 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011674 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011675 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011676 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011677
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011678 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011679}
11680
11681
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011682RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011683 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011684 ASSERT(args.length() == 0);
11685
11686#ifdef DEBUG
11687 // Print the scopes for the top frame.
11688 StackFrameLocator locator;
11689 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011690 for (ScopeIterator it(isolate, frame, 0);
11691 !it.Done();
11692 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011693 it.DebugPrint();
11694 }
11695#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011696 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011697}
11698
11699
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011700RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011701 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011702 ASSERT(args.length() == 1);
11703
11704 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011705 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011706 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11707 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011708 if (!maybe_result->ToObject(&result)) return maybe_result;
11709 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011710
11711 // Count all archived V8 threads.
11712 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011713 for (ThreadState* thread =
11714 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011715 thread != NULL;
11716 thread = thread->Next()) {
11717 n++;
11718 }
11719
11720 // Total number of threads is current thread and archived threads.
11721 return Smi::FromInt(n + 1);
11722}
11723
11724
11725static const int kThreadDetailsCurrentThreadIndex = 0;
11726static const int kThreadDetailsThreadIdIndex = 1;
11727static const int kThreadDetailsSize = 2;
11728
11729// Return an array with thread details
11730// args[0]: number: break id
11731// args[1]: number: thread index
11732//
11733// The array returned contains the following information:
11734// 0: Is current thread?
11735// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011736RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011737 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011738 ASSERT(args.length() == 2);
11739
11740 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011741 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011742 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11743 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011744 if (!maybe_check->ToObject(&check)) return maybe_check;
11745 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011746 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11747
11748 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011749 Handle<FixedArray> details =
11750 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011751
11752 // Thread index 0 is current thread.
11753 if (index == 0) {
11754 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011755 details->set(kThreadDetailsCurrentThreadIndex,
11756 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011757 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011758 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011759 } else {
11760 // Find the thread with the requested index.
11761 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011762 ThreadState* thread =
11763 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011764 while (index != n && thread != NULL) {
11765 thread = thread->Next();
11766 n++;
11767 }
11768 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011769 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011770 }
11771
11772 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011773 details->set(kThreadDetailsCurrentThreadIndex,
11774 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011775 details->set(kThreadDetailsThreadIdIndex,
11776 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011777 }
11778
11779 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011780 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011781}
11782
11783
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011784// Sets the disable break state
11785// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011786RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011787 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011788 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011789 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011790 isolate->debug()->set_disable_break(disable_break);
11791 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011792}
11793
11794
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011795RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011796 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011797 ASSERT(args.length() == 1);
11798
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011799 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011800 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011801 // Find the number of break points
11802 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011803 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011804 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011805 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011806 Handle<FixedArray>::cast(break_locations));
11807}
11808
11809
11810// Set a break point in a function
11811// args[0]: function
11812// args[1]: number: break source position (within the function source)
11813// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011814RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011815 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011816 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011817 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011818 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011819 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11820 RUNTIME_ASSERT(source_position >= 0);
11821 Handle<Object> break_point_object_arg = args.at<Object>(2);
11822
11823 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011824 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11825 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011826
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011827 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011828}
11829
11830
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011831Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11832 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011833 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011834 // Iterate the heap looking for SharedFunctionInfo generated from the
11835 // script. The inner most SharedFunctionInfo containing the source position
11836 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011837 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011838 // which is found is not compiled it is compiled and the heap is iterated
11839 // again as the compilation might create inner functions from the newly
11840 // compiled function and the actual requested break point might be in one of
11841 // these functions.
11842 bool done = false;
11843 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011844 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011845 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011846 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011847 { // Extra scope for iterator and no-allocation.
11848 isolate->heap()->EnsureHeapIsIterable();
11849 AssertNoAllocation no_alloc_during_heap_iteration;
11850 HeapIterator iterator;
11851 for (HeapObject* obj = iterator.next();
11852 obj != NULL; obj = iterator.next()) {
11853 if (obj->IsSharedFunctionInfo()) {
11854 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11855 if (shared->script() == *script) {
11856 // If the SharedFunctionInfo found has the requested script data and
11857 // contains the source position it is a candidate.
11858 int start_position = shared->function_token_position();
11859 if (start_position == RelocInfo::kNoPosition) {
11860 start_position = shared->start_position();
11861 }
11862 if (start_position <= position &&
11863 position <= shared->end_position()) {
11864 // If there is no candidate or this function is within the current
11865 // candidate this is the new candidate.
11866 if (target.is_null()) {
11867 target_start_position = start_position;
11868 target = shared;
11869 } else {
11870 if (target_start_position == start_position &&
11871 shared->end_position() == target->end_position()) {
11872 // If a top-level function contain only one function
11873 // declartion the source for the top-level and the
11874 // function is the same. In that case prefer the non
11875 // top-level function.
11876 if (!shared->is_toplevel()) {
11877 target_start_position = start_position;
11878 target = shared;
11879 }
11880 } else if (target_start_position <= start_position &&
11881 shared->end_position() <= target->end_position()) {
11882 // This containment check includes equality as a function
11883 // inside a top-level function can share either start or end
11884 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011885 target_start_position = start_position;
11886 target = shared;
11887 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011888 }
11889 }
11890 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011891 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011892 } // End for loop.
11893 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011894
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011895 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011896 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011897 }
11898
11899 // If the candidate found is compiled we are done. NOTE: when lazy
11900 // compilation of inner functions is introduced some additional checking
11901 // needs to be done here to compile inner functions.
11902 done = target->is_compiled();
11903 if (!done) {
11904 // If the candidate is not compiled compile it to reveal any inner
11905 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011906 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011907 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011908 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011909
11910 return *target;
11911}
11912
11913
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011914// Changes the state of a break point in a script and returns source position
11915// where break point was set. NOTE: Regarding performance see the NOTE for
11916// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011917// args[0]: script to set break point in
11918// args[1]: number: break source position (within the script source)
11919// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011920RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011921 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011922 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011923 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011924 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11925 RUNTIME_ASSERT(source_position >= 0);
11926 Handle<Object> break_point_object_arg = args.at<Object>(2);
11927
11928 // Get the script from the script wrapper.
11929 RUNTIME_ASSERT(wrapper->value()->IsScript());
11930 Handle<Script> script(Script::cast(wrapper->value()));
11931
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011932 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011933 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011934 if (!result->IsUndefined()) {
11935 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11936 // Find position within function. The script position might be before the
11937 // source position of the first function.
11938 int position;
11939 if (shared->start_position() > source_position) {
11940 position = 0;
11941 } else {
11942 position = source_position - shared->start_position();
11943 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011944 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011945 position += shared->start_position();
11946 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011947 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011948 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011949}
11950
11951
11952// Clear a break point
11953// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011954RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011955 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011956 ASSERT(args.length() == 1);
11957 Handle<Object> break_point_object_arg = args.at<Object>(0);
11958
11959 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011960 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011961
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011962 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011963}
11964
11965
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011966// Change the state of break on exceptions.
11967// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11968// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011969RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011970 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011971 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011972 RUNTIME_ASSERT(args[0]->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011973 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011974
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011975 // If the number doesn't match an enum value, the ChangeBreakOnException
11976 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011977 ExceptionBreakType type =
11978 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011979 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011980 isolate->debug()->ChangeBreakOnException(type, enable);
11981 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011982}
11983
11984
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011985// Returns the state of break on exceptions
11986// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011987RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011988 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011989 ASSERT(args.length() == 1);
11990 RUNTIME_ASSERT(args[0]->IsNumber());
11991
11992 ExceptionBreakType type =
11993 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011994 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011995 return Smi::FromInt(result);
11996}
11997
11998
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011999// Prepare for stepping
12000// args[0]: break id for checking execution state
12001// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000012002// args[2]: number of times to perform the step, for step out it is the number
12003// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012004RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012005 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012006 ASSERT(args.length() == 3);
12007 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012008 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012009 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
12010 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012011 if (!maybe_check->ToObject(&check)) return maybe_check;
12012 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012013 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012014 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012015 }
12016
12017 // Get the step action and check validity.
12018 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
12019 if (step_action != StepIn &&
12020 step_action != StepNext &&
12021 step_action != StepOut &&
12022 step_action != StepInMin &&
12023 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012024 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012025 }
12026
12027 // Get the number of steps.
12028 int step_count = NumberToInt32(args[2]);
12029 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012030 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012031 }
12032
ager@chromium.orga1645e22009-09-09 19:27:10 +000012033 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012034 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000012035
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012036 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012037 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
12038 step_count);
12039 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012040}
12041
12042
12043// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012044RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012045 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012046 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012047 isolate->debug()->ClearStepping();
12048 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012049}
12050
12051
12052// Creates a copy of the with context chain. The copy of the context chain is
12053// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012054static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
12055 Handle<JSFunction> function,
12056 Handle<Context> base,
12057 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012058 int inlined_jsframe_index) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012059 HandleScope scope(isolate);
12060 List<Handle<ScopeInfo> > scope_chain;
12061 List<Handle<Context> > context_chain;
12062
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012063 ScopeIterator it(isolate, frame, inlined_jsframe_index);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012064 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
12065 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
12066 ASSERT(!it.Done());
12067 scope_chain.Add(it.CurrentScopeInfo());
12068 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012069 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012070
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012071 // At the end of the chain. Return the base context to link to.
12072 Handle<Context> context = base;
12073
12074 // Iteratively copy and or materialize the nested contexts.
12075 while (!scope_chain.is_empty()) {
12076 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
12077 Handle<Context> current = context_chain.RemoveLast();
12078 ASSERT(!(scope_info->HasContext() & current.is_null()));
12079
12080 if (scope_info->Type() == CATCH_SCOPE) {
12081 Handle<String> name(String::cast(current->extension()));
12082 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
12083 context =
12084 isolate->factory()->NewCatchContext(function,
12085 context,
12086 name,
12087 thrown_object);
12088 } else if (scope_info->Type() == BLOCK_SCOPE) {
12089 // Materialize the contents of the block scope into a JSObject.
12090 Handle<JSObject> block_scope_object =
12091 MaterializeBlockScope(isolate, current);
12092 if (block_scope_object.is_null()) {
12093 return Handle<Context>::null();
12094 }
12095 // Allocate a new function context for the debug evaluation and set the
12096 // extension object.
12097 Handle<Context> new_context =
12098 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12099 function);
12100 new_context->set_extension(*block_scope_object);
12101 new_context->set_previous(*context);
12102 context = new_context;
12103 } else {
12104 ASSERT(scope_info->Type() == WITH_SCOPE);
12105 ASSERT(current->IsWithContext());
12106 Handle<JSObject> extension(JSObject::cast(current->extension()));
12107 context =
12108 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000012109 }
erikcorry0ad885c2011-11-21 13:51:57 +000012110 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012111
12112 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012113}
12114
12115
12116// Helper function to find or create the arguments object for
12117// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012118static Handle<Object> GetArgumentsObject(Isolate* isolate,
12119 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012120 FrameInspector* frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012121 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012122 Handle<Context> function_context) {
12123 // Try to find the value of 'arguments' to pass as parameter. If it is not
12124 // found (that is the debugged function does not reference 'arguments' and
12125 // does not support eval) then create an 'arguments' object.
12126 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012127 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012128 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012129 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012130 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012131 }
12132 }
12133
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012134 if (scope_info->HasHeapAllocatedLocals()) {
12135 VariableMode mode;
12136 InitializationFlag init_flag;
12137 index = scope_info->ContextSlotIndex(
12138 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012139 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012140 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012141 }
12142 }
12143
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012144 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
12145 int length = frame_inspector->GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012146 Handle<JSObject> arguments =
12147 isolate->factory()->NewArgumentsObject(function, length);
12148 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012149
12150 AssertNoAllocation no_gc;
12151 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012152 for (int i = 0; i < length; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012153 array->set(i, frame_inspector->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012154 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012155 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012156 return arguments;
12157}
12158
12159
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012160static const char kSourceStr[] =
12161 "(function(arguments,__source__){return eval(__source__);})";
12162
12163
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012164// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000012165// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012166// extension part has all the parameters and locals of the function on the
12167// stack frame. A function which calls eval with the code to evaluate is then
12168// compiled in this context and called in this context. As this context
12169// replaces the context of the function on the stack frame a new (empty)
12170// function is created as well to be used as the closure for the context.
12171// This function and the context acts as replacements for the function on the
12172// stack frame presenting the same view of the values of parameters and
12173// local variables as if the piece of JavaScript was evaluated at the point
12174// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012175RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012176 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012177
12178 // Check the execution state and decode arguments frame and source to be
12179 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012180 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012181 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012182 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12183 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012184 if (!maybe_check_result->ToObject(&check_result)) {
12185 return maybe_check_result;
12186 }
12187 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012188 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012189 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012190 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
12191 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012192 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012193
12194 // Handle the processing of break.
12195 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012196
12197 // Get the frame where the debugging is performed.
12198 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012199 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012200 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012201 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
12202 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012203 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012204
12205 // Traverse the saved contexts chain to find the active context for the
12206 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012207 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12208
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012209 SaveContext savex(isolate);
12210 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012211
12212 // Create the (empty) function replacing the function on the stack frame for
12213 // the purpose of evaluating in the context created below. It is important
12214 // that this function does not describe any parameters and local variables
12215 // in the context. If it does then this will cause problems with the lookup
12216 // in Context::Lookup, where context slots for parameters and local variables
12217 // are looked at before the extension object.
12218 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012219 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12220 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012221 go_between->set_context(function->context());
12222#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012223 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12224 ASSERT(go_between_scope_info->ParameterCount() == 0);
12225 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012226#endif
12227
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012228 // Materialize the content of the local scope into a JSObject.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012229 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
12230 isolate, frame, &frame_inspector);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012231 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012232
12233 // Allocate a new context for the debug evaluation and set the extension
12234 // object build.
12235 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012236 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12237 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012238 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012239 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012240 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012241 Handle<Context> function_context;
12242 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012243 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012244 function_context = Handle<Context>(frame_context->declaration_context());
12245 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012246 context = CopyNestedScopeContextChain(isolate,
12247 go_between,
12248 context,
12249 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012250 inlined_jsframe_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012251
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012252 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012253 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012254 context =
12255 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012256 }
12257
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012258 // Wrap the evaluation statement in a new function compiled in the newly
12259 // created context. The function has one parameter which has to be called
12260 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012261 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012262 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012263
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012264 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012265 isolate->factory()->NewStringFromAscii(
12266 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012267
12268 // Currently, the eval code will be executed in non-strict mode,
12269 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012270 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012271 Compiler::CompileEval(function_source,
12272 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012273 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012274 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012275 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012276 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012277 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012278 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012279
12280 // Invoke the result of the compilation to get the evaluation function.
12281 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012282 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012283 Handle<Object> evaluation_function =
12284 Execution::Call(compiled_function, receiver, 0, NULL,
12285 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012286 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012287
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012288 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012289 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012290 &frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012291 scope_info,
12292 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012293
12294 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012295 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012296 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012297 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12298 receiver,
12299 ARRAY_SIZE(argv),
12300 argv,
12301 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012302 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012303
12304 // Skip the global proxy as it has no properties and always delegates to the
12305 // real global object.
12306 if (result->IsJSGlobalProxy()) {
12307 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12308 }
12309
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012310 return *result;
12311}
12312
12313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012314RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012315 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012316
12317 // Check the execution state and decode arguments frame and source to be
12318 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012319 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012320 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012321 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12322 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012323 if (!maybe_check_result->ToObject(&check_result)) {
12324 return maybe_check_result;
12325 }
12326 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012327 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
12328 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012329 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012330
12331 // Handle the processing of break.
12332 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012333
12334 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012335 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012336 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012337 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012338 top = top->prev();
12339 }
12340 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012341 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012342 }
12343
12344 // Get the global context now set to the top context from before the
12345 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012346 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012347
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012348 bool is_global = true;
12349
12350 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000012351 // Create a new with context with the additional context information between
12352 // the context of the debugged function and the eval code to be executed.
12353 context = isolate->factory()->NewWithContext(
12354 Handle<JSFunction>(context->closure()),
12355 context,
12356 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012357 is_global = false;
12358 }
12359
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012360 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012361 // Currently, the eval code will be executed in non-strict mode,
12362 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012363 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012364 Compiler::CompileEval(source,
12365 context,
12366 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012367 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012368 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012369 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012370 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012371 Handle<JSFunction>(
12372 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12373 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012374
12375 // Invoke the result of the compilation to get the evaluation function.
12376 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012377 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012378 Handle<Object> result =
12379 Execution::Call(compiled_function, receiver, 0, NULL,
12380 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012381 // Clear the oneshot breakpoints so that the debugger does not step further.
12382 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012383 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012384 return *result;
12385}
12386
12387
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012388RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012389 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012390 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012391
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012392 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012393 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012394
12395 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012396 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012397 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12398 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12399 // because using
12400 // instances->set(i, *GetScriptWrapper(script))
12401 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012402 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012403 Handle<JSValue> wrapper = GetScriptWrapper(script);
12404 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012405 }
12406
12407 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012408 Handle<JSObject> result =
12409 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012410 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012411 return *result;
12412}
12413
12414
12415// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012416static int DebugReferencedBy(HeapIterator* iterator,
12417 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012418 Object* instance_filter, int max_references,
12419 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012420 JSFunction* arguments_function) {
12421 NoHandleAllocation ha;
12422 AssertNoAllocation no_alloc;
12423
12424 // Iterate the heap.
12425 int count = 0;
12426 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012427 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012428 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012429 (max_references == 0 || count < max_references)) {
12430 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012431 if (heap_obj->IsJSObject()) {
12432 // Skip context extension objects and argument arrays as these are
12433 // checked in the context of functions using them.
12434 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012435 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012436 obj->map()->constructor() == arguments_function) {
12437 continue;
12438 }
12439
12440 // Check if the JS object has a reference to the object looked for.
12441 if (obj->ReferencesObject(target)) {
12442 // Check instance filter if supplied. This is normally used to avoid
12443 // references from mirror objects (see Runtime_IsInPrototypeChain).
12444 if (!instance_filter->IsUndefined()) {
12445 Object* V = obj;
12446 while (true) {
12447 Object* prototype = V->GetPrototype();
12448 if (prototype->IsNull()) {
12449 break;
12450 }
12451 if (instance_filter == prototype) {
12452 obj = NULL; // Don't add this object.
12453 break;
12454 }
12455 V = prototype;
12456 }
12457 }
12458
12459 if (obj != NULL) {
12460 // Valid reference found add to instance array if supplied an update
12461 // count.
12462 if (instances != NULL && count < instances_size) {
12463 instances->set(count, obj);
12464 }
12465 last = obj;
12466 count++;
12467 }
12468 }
12469 }
12470 }
12471
12472 // Check for circular reference only. This can happen when the object is only
12473 // referenced from mirrors and has a circular reference in which case the
12474 // object is not really alive and would have been garbage collected if not
12475 // referenced from the mirror.
12476 if (count == 1 && last == target) {
12477 count = 0;
12478 }
12479
12480 // Return the number of referencing objects found.
12481 return count;
12482}
12483
12484
12485// Scan the heap for objects with direct references to an object
12486// args[0]: the object to find references to
12487// args[1]: constructor function for instances to exclude (Mirror)
12488// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012489RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012490 ASSERT(args.length() == 3);
12491
12492 // First perform a full GC in order to avoid references from dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012493 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12494 "%DebugReferencedBy");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012495 // The heap iterator reserves the right to do a GC to make the heap iterable.
12496 // Due to the GC above we know it won't need to do that, but it seems cleaner
12497 // to get the heap iterator constructed before we start having unprotected
12498 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012499
12500 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012501 CONVERT_ARG_CHECKED(JSObject, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012502 Object* instance_filter = args[1];
12503 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12504 instance_filter->IsJSObject());
12505 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12506 RUNTIME_ASSERT(max_references >= 0);
12507
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012508
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012509 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012510 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012511 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012512 JSFunction* arguments_function =
12513 JSFunction::cast(arguments_boilerplate->map()->constructor());
12514
12515 // Get the number of referencing objects.
12516 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012517 HeapIterator heap_iterator;
12518 count = DebugReferencedBy(&heap_iterator,
12519 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012520 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012521
12522 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012523 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012524 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012525 if (!maybe_object->ToObject(&object)) return maybe_object;
12526 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012527 FixedArray* instances = FixedArray::cast(object);
12528
12529 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012530 // AllocateFixedArray above does not make the heap non-iterable.
12531 ASSERT(HEAP->IsHeapIterable());
12532 HeapIterator heap_iterator2;
12533 count = DebugReferencedBy(&heap_iterator2,
12534 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012535 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012536
12537 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012538 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012539 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012540 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012541 if (!maybe_result->ToObject(&result)) return maybe_result;
12542 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012543}
12544
12545
12546// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012547static int DebugConstructedBy(HeapIterator* iterator,
12548 JSFunction* constructor,
12549 int max_references,
12550 FixedArray* instances,
12551 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012552 AssertNoAllocation no_alloc;
12553
12554 // Iterate the heap.
12555 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012556 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012557 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012558 (max_references == 0 || count < max_references)) {
12559 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012560 if (heap_obj->IsJSObject()) {
12561 JSObject* obj = JSObject::cast(heap_obj);
12562 if (obj->map()->constructor() == constructor) {
12563 // Valid reference found add to instance array if supplied an update
12564 // count.
12565 if (instances != NULL && count < instances_size) {
12566 instances->set(count, obj);
12567 }
12568 count++;
12569 }
12570 }
12571 }
12572
12573 // Return the number of referencing objects found.
12574 return count;
12575}
12576
12577
12578// Scan the heap for objects constructed by a specific function.
12579// args[0]: the constructor to find instances of
12580// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012581RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012582 ASSERT(args.length() == 2);
12583
12584 // First perform a full GC in order to avoid dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012585 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12586 "%DebugConstructedBy");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012587
12588 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012589 CONVERT_ARG_CHECKED(JSFunction, constructor, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012590 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12591 RUNTIME_ASSERT(max_references >= 0);
12592
12593 // Get the number of referencing objects.
12594 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012595 HeapIterator heap_iterator;
12596 count = DebugConstructedBy(&heap_iterator,
12597 constructor,
12598 max_references,
12599 NULL,
12600 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012601
12602 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012603 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012604 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012605 if (!maybe_object->ToObject(&object)) return maybe_object;
12606 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012607 FixedArray* instances = FixedArray::cast(object);
12608
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012609 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012610 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012611 HeapIterator heap_iterator2;
12612 count = DebugConstructedBy(&heap_iterator2,
12613 constructor,
12614 max_references,
12615 instances,
12616 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012617
12618 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012619 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012620 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12621 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012622 if (!maybe_result->ToObject(&result)) return maybe_result;
12623 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012624 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012625}
12626
12627
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012628// Find the effective prototype object as returned by __proto__.
12629// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012630RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012631 ASSERT(args.length() == 1);
12632
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012633 CONVERT_ARG_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012634
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012635 // Use the __proto__ accessor.
12636 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012637}
12638
12639
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012640RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012641 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012642 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012643 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012644}
12645
12646
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012647RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012648#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012649 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012650 ASSERT(args.length() == 1);
12651 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012652 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012653 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012654 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012655 return Failure::Exception();
12656 }
12657 func->code()->PrintLn();
12658#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012659 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012660}
ager@chromium.org9085a012009-05-11 19:22:57 +000012661
12662
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012663RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012664#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012665 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012666 ASSERT(args.length() == 1);
12667 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012668 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012669 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012670 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012671 return Failure::Exception();
12672 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012673 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012674#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012675 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012676}
12677
12678
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012679RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012680 NoHandleAllocation ha;
12681 ASSERT(args.length() == 1);
12682
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012683 CONVERT_ARG_CHECKED(JSFunction, f, 0);
ager@chromium.org9085a012009-05-11 19:22:57 +000012684 return f->shared()->inferred_name();
12685}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012686
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012687
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012688static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12689 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012690 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012691 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012692 int counter = 0;
12693 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012694 for (HeapObject* obj = iterator->next();
12695 obj != NULL;
12696 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012697 ASSERT(obj != NULL);
12698 if (!obj->IsSharedFunctionInfo()) {
12699 continue;
12700 }
12701 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12702 if (shared->script() != script) {
12703 continue;
12704 }
12705 if (counter < buffer_size) {
12706 buffer->set(counter, shared);
12707 }
12708 counter++;
12709 }
12710 return counter;
12711}
12712
12713// For a script finds all SharedFunctionInfo's in the heap that points
12714// to this script. Returns JSArray of SharedFunctionInfo wrapped
12715// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012716RUNTIME_FUNCTION(MaybeObject*,
12717 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012718 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012719 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012720 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012721
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012722
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012723 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12724
12725 const int kBufferSize = 32;
12726
12727 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012728 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012729 int number;
12730 {
12731 isolate->heap()->EnsureHeapIsIterable();
12732 AssertNoAllocation no_allocations;
12733 HeapIterator heap_iterator;
12734 Script* scr = *script;
12735 FixedArray* arr = *array;
12736 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12737 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012738 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012739 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012740 isolate->heap()->EnsureHeapIsIterable();
12741 AssertNoAllocation no_allocations;
12742 HeapIterator heap_iterator;
12743 Script* scr = *script;
12744 FixedArray* arr = *array;
12745 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012746 }
12747
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012748 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012749 result->set_length(Smi::FromInt(number));
12750
12751 LiveEdit::WrapSharedFunctionInfos(result);
12752
12753 return *result;
12754}
12755
12756// For a script calculates compilation information about all its functions.
12757// The script source is explicitly specified by the second argument.
12758// The source of the actual script is not used, however it is important that
12759// all generated code keeps references to this particular instance of script.
12760// Returns a JSArray of compilation infos. The array is ordered so that
12761// each function with all its descendant is always stored in a continues range
12762// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012763RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012764 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012765 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012766 CONVERT_ARG_CHECKED(JSValue, script, 0);
12767 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012768 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12769
12770 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12771
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012772 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012773 return Failure::Exception();
12774 }
12775
12776 return result;
12777}
12778
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012779// Changes the source of the script to a new_source.
12780// If old_script_name is provided (i.e. is a String), also creates a copy of
12781// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012782RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012783 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012784 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012785 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
12786 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012787 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012788
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012789 RUNTIME_ASSERT(original_script_value->value()->IsScript());
12790 Handle<Script> original_script(Script::cast(original_script_value->value()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012791
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012792 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12793 new_source,
12794 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012795
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012796 if (old_script->IsScript()) {
12797 Handle<Script> script_handle(Script::cast(old_script));
12798 return *(GetScriptWrapper(script_handle));
12799 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012800 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012801 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012802}
12803
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012804
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012805RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012806 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012807 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012808 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012809 return LiveEdit::FunctionSourceUpdated(shared_info);
12810}
12811
12812
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012813// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012814RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012815 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012816 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012817 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
12818 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012819
ager@chromium.orgac091b72010-05-05 07:34:42 +000012820 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012821}
12822
12823// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012824RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012825 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012826 HandleScope scope(isolate);
12827 Handle<Object> function_object(args[0], isolate);
12828 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012829
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012830 if (function_object->IsJSValue()) {
12831 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12832 if (script_object->IsJSValue()) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012833 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
12834 Script* script = Script::cast(JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012835 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012836 }
12837
12838 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12839 } else {
12840 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12841 // and we check it in this function.
12842 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012843
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012844 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012845}
12846
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012847
12848// In a code of a parent function replaces original function as embedded object
12849// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012850RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012851 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012852 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012853
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012854 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
12855 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
12856 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012857
12858 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12859 subst_wrapper);
12860
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012861 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012862}
12863
12864
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012865// Updates positions of a shared function info (first parameter) according
12866// to script source change. Text change is described in second parameter as
12867// array of groups of 3 numbers:
12868// (change_begin, change_end, change_end_new_position).
12869// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012870RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012871 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012872 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012873 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12874 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012875
ager@chromium.orgac091b72010-05-05 07:34:42 +000012876 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012877}
12878
12879
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012880// For array of SharedFunctionInfo's (each wrapped in JSValue)
12881// checks that none of them have activations on stacks (of any thread).
12882// Returns array of the same length with corresponding results of
12883// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012884RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012885 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012886 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012887 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12888 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012889
ager@chromium.org357bf652010-04-12 11:30:10 +000012890 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012891}
12892
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012893// Compares 2 strings line-by-line, then token-wise and returns diff in form
12894// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12895// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012896RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012897 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012898 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012899 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
12900 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012901
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012902 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012903}
12904
12905
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012906// A testing entry. Returns statement position which is the closest to
12907// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012908RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012909 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012910 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012911 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012912 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12913
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012914 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012915
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012916 if (code->kind() != Code::FUNCTION &&
12917 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012918 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012919 }
12920
12921 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012922 int closest_pc = 0;
12923 int distance = kMaxInt;
12924 while (!it.done()) {
12925 int statement_position = static_cast<int>(it.rinfo()->data());
12926 // Check if this break point is closer that what was previously found.
12927 if (source_position <= statement_position &&
12928 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012929 closest_pc =
12930 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012931 distance = statement_position - source_position;
12932 // Check whether we can't get any closer.
12933 if (distance == 0) break;
12934 }
12935 it.next();
12936 }
12937
12938 return Smi::FromInt(closest_pc);
12939}
12940
12941
ager@chromium.org357bf652010-04-12 11:30:10 +000012942// Calls specified function with or without entering the debugger.
12943// This is used in unit tests to run code as if debugger is entered or simply
12944// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012945RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012946 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012947 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012948 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12949 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
ager@chromium.org357bf652010-04-12 11:30:10 +000012950
12951 Handle<Object> result;
12952 bool pending_exception;
12953 {
12954 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012955 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012956 &pending_exception);
12957 } else {
12958 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012959 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012960 &pending_exception);
12961 }
12962 }
12963 if (!pending_exception) {
12964 return *result;
12965 } else {
12966 return Failure::Exception();
12967 }
12968}
12969
12970
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012971// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012972RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012973 CONVERT_ARG_CHECKED(String, arg, 0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012974 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012975 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12976 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012977 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012978}
12979
12980
12981// Performs a GC.
12982// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012983RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012984 isolate->heap()->CollectAllGarbage(true, "%CollectGarbage");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012985 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012986}
12987
12988
12989// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012990RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012991 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012992 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012993 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012994 }
12995 return Smi::FromInt(usage);
12996}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012997
12998
12999// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013000RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013001#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013002 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013003#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013004 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013005#endif
13006}
13007
13008
13009// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013010RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013011#ifdef LIVE_OBJECT_LIST
13012 return LiveObjectList::Capture();
13013#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013014 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013015#endif
13016}
13017
13018
13019// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013020RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013021#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013022 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013023 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000013024 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013025#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013026 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013027#endif
13028}
13029
13030
13031// Generates the response to a debugger request for a dump of the objects
13032// contained in the difference between the captured live object lists
13033// specified by id1 and id2.
13034// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13035// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013036RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013037#ifdef LIVE_OBJECT_LIST
13038 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013039 CONVERT_SMI_ARG_CHECKED(id1, 0);
13040 CONVERT_SMI_ARG_CHECKED(id2, 1);
13041 CONVERT_SMI_ARG_CHECKED(start, 2);
13042 CONVERT_SMI_ARG_CHECKED(count, 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013043 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013044 EnterDebugger enter_debugger;
13045 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
13046#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013047 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013048#endif
13049}
13050
13051
13052// Gets the specified object as requested by the debugger.
13053// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013054RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013055#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013056 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013057 Object* result = LiveObjectList::GetObj(obj_id);
13058 return result;
13059#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013060 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013061#endif
13062}
13063
13064
13065// Gets the obj id for the specified address if valid.
13066// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013067RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013068#ifdef LIVE_OBJECT_LIST
13069 HandleScope scope;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013070 CONVERT_ARG_HANDLE_CHECKED(String, address, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013071 Object* result = LiveObjectList::GetObjId(address);
13072 return result;
13073#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013074 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013075#endif
13076}
13077
13078
13079// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013080RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013081#ifdef LIVE_OBJECT_LIST
13082 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013083 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013084 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
13085 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
13086 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
13087 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013088 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 5);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013089
13090 Handle<JSObject> instance_filter;
13091 if (args[1]->IsJSObject()) {
13092 instance_filter = args.at<JSObject>(1);
13093 }
13094 bool verbose = false;
13095 if (args[2]->IsBoolean()) {
13096 verbose = args[2]->IsTrue();
13097 }
13098 int start = 0;
13099 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013100 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013101 }
13102 int limit = Smi::kMaxValue;
13103 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013104 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013105 }
13106
13107 return LiveObjectList::GetObjRetainers(obj_id,
13108 instance_filter,
13109 verbose,
13110 start,
13111 limit,
13112 filter_obj);
13113#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013114 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013115#endif
13116}
13117
13118
13119// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013120RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013121#ifdef LIVE_OBJECT_LIST
13122 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013123 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
13124 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013125 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
13126
13127 Handle<JSObject> instance_filter;
13128 if (args[2]->IsJSObject()) {
13129 instance_filter = args.at<JSObject>(2);
13130 }
13131
13132 Object* result =
13133 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
13134 return result;
13135#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013136 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013137#endif
13138}
13139
13140
13141// Generates the response to a debugger request for a list of all
13142// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013143RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013144#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013145 CONVERT_SMI_ARG_CHECKED(start, 0);
13146 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013147 return LiveObjectList::Info(start, count);
13148#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013149 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013150#endif
13151}
13152
13153
13154// Gets a dump of the specified object as requested by the debugger.
13155// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013156RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013157#ifdef LIVE_OBJECT_LIST
13158 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013159 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013160 Object* result = LiveObjectList::PrintObj(obj_id);
13161 return result;
13162#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013163 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013164#endif
13165}
13166
13167
13168// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013169RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013170#ifdef LIVE_OBJECT_LIST
13171 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013172 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013173#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013174 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013175#endif
13176}
13177
13178
13179// Generates the response to a debugger request for a summary of the types
13180// of objects in the difference between the captured live object lists
13181// specified by id1 and id2.
13182// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13183// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013184RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013185#ifdef LIVE_OBJECT_LIST
13186 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013187 CONVERT_SMI_ARG_CHECKED(id1, 0);
13188 CONVERT_SMI_ARG_CHECKED(id2, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013189 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013190
13191 EnterDebugger enter_debugger;
13192 return LiveObjectList::Summarize(id1, id2, filter_obj);
13193#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013194 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013195#endif
13196}
13197
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013198#endif // ENABLE_DEBUGGER_SUPPORT
13199
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013200
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013201RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013202 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013203 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013204 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013205}
13206
13207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013208RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013209 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013210 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013211 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013212}
13213
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013214
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013215// Finds the script object from the script data. NOTE: This operation uses
13216// heap traversal to find the function generated for the source position
13217// for the requested break point. For lazily compiled functions several heap
13218// traversals might be required rendering this operation as a rather slow
13219// operation. However for setting break points which is normally done through
13220// some kind of user interaction the performance is not crucial.
13221static Handle<Object> Runtime_GetScriptFromScriptName(
13222 Handle<String> script_name) {
13223 // Scan the heap for Script objects to find the script with the requested
13224 // script data.
13225 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013226 script_name->GetHeap()->EnsureHeapIsIterable();
13227 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013228 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013229 HeapObject* obj = NULL;
13230 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013231 // If a script is found check if it has the script data requested.
13232 if (obj->IsScript()) {
13233 if (Script::cast(obj)->name()->IsString()) {
13234 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13235 script = Handle<Script>(Script::cast(obj));
13236 }
13237 }
13238 }
13239 }
13240
13241 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013242 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013243
13244 // Return the script found.
13245 return GetScriptWrapper(script);
13246}
13247
13248
13249// Get the script object from script data. NOTE: Regarding performance
13250// see the NOTE for GetScriptFromScriptData.
13251// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013252RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013253 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013254
13255 ASSERT(args.length() == 1);
13256
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013257 CONVERT_ARG_CHECKED(String, script_name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013258
13259 // Find the requested script.
13260 Handle<Object> result =
13261 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13262 return *result;
13263}
13264
13265
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013266// Determines whether the given stack frame should be displayed in
13267// a stack trace. The caller is the error constructor that asked
13268// for the stack trace to be collected. The first time a construct
13269// call to this function is encountered it is skipped. The seen_caller
13270// in/out parameter is used to remember if the caller has been seen
13271// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013272static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13273 Object* caller,
13274 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013275 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013276 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013277 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013278 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013279 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13280 Object* raw_fun = frame->function();
13281 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013282 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013283 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013284 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013285 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013286 *seen_caller = true;
13287 return false;
13288 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013289 // Skip all frames until we've seen the caller.
13290 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013291 // Also, skip non-visible built-in functions and any call with the builtins
13292 // object as receiver, so as to not reveal either the builtins object or
13293 // an internal function.
13294 // The --builtins-in-stack-traces command line flag allows including
13295 // internal call sites in the stack trace for debugging purposes.
13296 if (!FLAG_builtins_in_stack_traces) {
13297 JSFunction* fun = JSFunction::cast(raw_fun);
13298 if (frame->receiver()->IsJSBuiltinsObject() ||
13299 (fun->IsBuiltin() && !fun->shared()->native())) {
13300 return false;
13301 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013302 }
13303 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013304}
13305
13306
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013307// Collect the raw data for a stack trace. Returns an array of 4
13308// element segments each containing a receiver, function, code and
13309// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013310RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013311 ASSERT_EQ(args.length(), 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013312 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013313 Handle<Object> caller = args.at<Object>(1);
13314 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013315
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013316 HandleScope scope(isolate);
13317 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013318
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013319 limit = Max(limit, 0); // Ensure that limit is not negative.
13320 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013321 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013322 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013323
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013324 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013325 // If the caller parameter is a function we skip frames until we're
13326 // under it before starting to collect.
13327 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013328 int cursor = 0;
13329 int frames_seen = 0;
13330 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013331 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013332 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013333 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013334 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013335 // Set initial size to the maximum inlining level + 1 for the outermost
13336 // function.
13337 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013338 frame->Summarize(&frames);
13339 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013340 if (cursor + 4 > elements->length()) {
13341 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13342 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013343 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013344 for (int i = 0; i < cursor; i++) {
13345 new_elements->set(i, elements->get(i));
13346 }
13347 elements = new_elements;
13348 }
13349 ASSERT(cursor + 4 <= elements->length());
13350
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013351 Handle<Object> recv = frames[i].receiver();
13352 Handle<JSFunction> fun = frames[i].function();
13353 Handle<Code> code = frames[i].code();
13354 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013355 elements->set(cursor++, *recv);
13356 elements->set(cursor++, *fun);
13357 elements->set(cursor++, *code);
13358 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013359 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013360 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013361 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013362 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013363 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013364 // Capture and attach a more detailed stack trace if necessary.
13365 isolate->CaptureAndSetCurrentStackTraceFor(error_object);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013366 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013367 return *result;
13368}
13369
13370
ager@chromium.org3811b432009-10-28 14:53:37 +000013371// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013372RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013373 ASSERT_EQ(args.length(), 0);
13374
13375 NoHandleAllocation ha;
13376
13377 const char* version_string = v8::V8::GetVersion();
13378
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013379 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13380 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013381}
13382
13383
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013384RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013385 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013386 OS::PrintError("abort: %s\n",
13387 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013388 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013389 OS::Abort();
13390 UNREACHABLE();
13391 return NULL;
13392}
13393
13394
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013395RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013396 // This is only called from codegen, so checks might be more lax.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013397 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013398 Object* key = args[1];
13399
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013400 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013401 Object* o = cache->get(finger_index);
13402 if (o == key) {
13403 // The fastest case: hit the same place again.
13404 return cache->get(finger_index + 1);
13405 }
13406
13407 for (int i = finger_index - 2;
13408 i >= JSFunctionResultCache::kEntriesIndex;
13409 i -= 2) {
13410 o = cache->get(i);
13411 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013412 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013413 return cache->get(i + 1);
13414 }
13415 }
13416
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013417 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013418 ASSERT(size <= cache->length());
13419
13420 for (int i = size - 2; i > finger_index; i -= 2) {
13421 o = cache->get(i);
13422 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013423 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013424 return cache->get(i + 1);
13425 }
13426 }
13427
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013428 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013429 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013430
13431 Handle<JSFunctionResultCache> cache_handle(cache);
13432 Handle<Object> key_handle(key);
13433 Handle<Object> value;
13434 {
13435 Handle<JSFunction> factory(JSFunction::cast(
13436 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13437 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013438 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013439 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013440 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013441 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013442 value = Execution::Call(factory,
13443 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013444 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013445 argv,
13446 &pending_exception);
13447 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013448 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013449
13450#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013451 if (FLAG_verify_heap) {
13452 cache_handle->JSFunctionResultCacheVerify();
13453 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013454#endif
13455
13456 // Function invocation may have cleared the cache. Reread all the data.
13457 finger_index = cache_handle->finger_index();
13458 size = cache_handle->size();
13459
13460 // If we have spare room, put new data into it, otherwise evict post finger
13461 // entry which is likely to be the least recently used.
13462 int index = -1;
13463 if (size < cache_handle->length()) {
13464 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13465 index = size;
13466 } else {
13467 index = finger_index + JSFunctionResultCache::kEntrySize;
13468 if (index == cache_handle->length()) {
13469 index = JSFunctionResultCache::kEntriesIndex;
13470 }
13471 }
13472
13473 ASSERT(index % 2 == 0);
13474 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13475 ASSERT(index < cache_handle->length());
13476
13477 cache_handle->set(index, *key_handle);
13478 cache_handle->set(index + 1, *value);
13479 cache_handle->set_finger_index(index);
13480
13481#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013482 if (FLAG_verify_heap) {
13483 cache_handle->JSFunctionResultCacheVerify();
13484 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013485#endif
13486
13487 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013488}
13489
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013490
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013491RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013492 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013493 CONVERT_ARG_HANDLE_CHECKED(String, type, 0);
13494 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013495 return *isolate->factory()->NewJSMessageObject(
13496 type,
13497 arguments,
13498 0,
13499 0,
13500 isolate->factory()->undefined_value(),
13501 isolate->factory()->undefined_value(),
13502 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013503}
13504
13505
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013506RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013507 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013508 return message->type();
13509}
13510
13511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013512RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013513 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013514 return message->arguments();
13515}
13516
13517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013518RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013519 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013520 return Smi::FromInt(message->start_position());
13521}
13522
13523
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013524RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013525 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013526 return message->script();
13527}
13528
13529
kasper.lund44510672008-07-25 07:37:58 +000013530#ifdef DEBUG
13531// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13532// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013533RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013534 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013535 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013536#define COUNT_ENTRY(Name, argc, ressize) + 1
13537 int entry_count = 0
13538 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13539 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13540 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13541#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013542 Factory* factory = isolate->factory();
13543 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013544 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013545 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013546#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013547 { \
13548 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013549 Handle<String> name; \
13550 /* Inline runtime functions have an underscore in front of the name. */ \
13551 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013552 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013553 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13554 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013555 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013556 Vector<const char>(#Name, StrLength(#Name))); \
13557 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013558 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013559 pair_elements->set(0, *name); \
13560 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013561 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013562 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013563 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013564 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013565 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013566 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013567 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013568 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013569#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013570 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013571 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013572 return *result;
13573}
kasper.lund44510672008-07-25 07:37:58 +000013574#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013575
13576
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013577RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013578 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013579 CONVERT_ARG_CHECKED(String, format, 0);
13580 CONVERT_ARG_CHECKED(JSArray, elms, 1);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013581 String::FlatContent format_content = format->GetFlatContent();
13582 RUNTIME_ASSERT(format_content.IsAscii());
13583 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013584 LOGGER->LogRuntime(chars, elms);
13585 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013586}
13587
13588
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013589RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013590 UNREACHABLE(); // implemented as macro in the parser
13591 return NULL;
13592}
13593
13594
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013595#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13596 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013597 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013598 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13599 }
13600
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013601ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013602ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13603ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13604ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13605ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13606ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13607ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13608ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13609ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13610ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13611ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13612ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13613ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13614ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13615
13616#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13617
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013618
13619RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13620 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013621 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
13622 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013623 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13624}
13625
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013626// ----------------------------------------------------------------------------
13627// Implementation of Runtime
13628
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013629#define F(name, number_of_args, result_size) \
13630 { Runtime::k##name, Runtime::RUNTIME, #name, \
13631 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013632
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013633
13634#define I(name, number_of_args, result_size) \
13635 { Runtime::kInline##name, Runtime::INLINE, \
13636 "_" #name, NULL, number_of_args, result_size },
13637
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013638static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013639 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013640 INLINE_FUNCTION_LIST(I)
13641 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013642};
13643
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013644
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013645MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13646 Object* dictionary) {
13647 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013648 ASSERT(dictionary != NULL);
13649 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13650 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013651 Object* name_symbol;
13652 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013653 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013654 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13655 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013656 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013657 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13658 String::cast(name_symbol),
13659 Smi::FromInt(i),
13660 PropertyDetails(NONE, NORMAL));
13661 if (!maybe_dictionary->ToObject(&dictionary)) {
13662 // Non-recoverable failure. Calling code must restart heap
13663 // initialization.
13664 return maybe_dictionary;
13665 }
13666 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013667 }
13668 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013669}
13670
13671
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013672const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13673 Heap* heap = name->GetHeap();
13674 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013675 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013676 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013677 int function_index = Smi::cast(smi_index)->value();
13678 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013679 }
13680 return NULL;
13681}
13682
13683
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013684const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013685 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13686}
13687
13688
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013689void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013690 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013691 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013692 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013693 if (isolate->heap()->new_space()->AddFreshPage()) {
13694 return;
13695 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013696 // Try to do a garbage collection; ignore it if it fails. The C
13697 // entry stub will throw an out-of-memory exception in that case.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013698 isolate->heap()->CollectGarbage(failure->allocation_space(),
13699 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013700 } else {
13701 // Handle last resort GC and make sure to allow future allocations
13702 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013703 isolate->counters()->gc_last_resort_from_js()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013704 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13705 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013706 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013707}
13708
13709
13710} } // namespace v8::internal