blob: 0726b3d68aea560e6603f98980a61070e42d458f [file] [log] [blame]
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000043#include "date.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000045#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000046#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000048#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000049#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000050#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000051#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000052#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000053#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000054#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000055#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000057#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000058#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000059#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000060#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000061#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062
kasperl@chromium.org71affb52009-05-26 05:44:31 +000063namespace v8 {
64namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000065
66
ager@chromium.org3e875802009-06-29 08:26:34 +000067#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000068 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000069
70// Cast the given object to a value of the specified type and store
71// it in a variable with the given name. If the object is not of the
72// expected type call IllegalOperation and return.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073#define CONVERT_ARG_CHECKED(Type, name, index) \
74 RUNTIME_ASSERT(args[index]->Is##Type()); \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000075 Type* name = Type::cast(args[index]);
76
77#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index) \
78 RUNTIME_ASSERT(args[index]->Is##Type()); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000079 Handle<Type> name = args.at<Type>(index);
80
kasper.lundbd3ec4e2008-07-09 11:06:54 +000081// Cast the given object to a boolean and store it in a variable with
82// the given name. If the object is not a boolean call IllegalOperation
83// and return.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000084#define CONVERT_BOOLEAN_ARG_CHECKED(name, index) \
85 RUNTIME_ASSERT(args[index]->IsBoolean()); \
86 bool name = args[index]->IsTrue();
kasper.lundbd3ec4e2008-07-09 11:06:54 +000087
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000088// Cast the given argument to a Smi and store its value in an int variable
89// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000090// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000091#define CONVERT_SMI_ARG_CHECKED(name, index) \
92 RUNTIME_ASSERT(args[index]->IsSmi()); \
93 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000094
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000095// Cast the given argument to a double and store it in a variable with
96// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000098#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
99 RUNTIME_ASSERT(args[index]->IsNumber()); \
100 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000101
102// Call the specified converter on the object *comand store the result in
103// a variable of the specified type with the given name. If the
104// object is not a Number call IllegalOperation and return.
105#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
106 RUNTIME_ASSERT(obj->IsNumber()); \
107 type name = NumberTo##Type(obj);
108
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000109
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000110// Cast the given argument to PropertyDetails and store its value in a
111// variable with the given name. If the argument is not a Smi call
112// IllegalOperation and return.
113#define CONVERT_PROPERTY_DETAILS_CHECKED(name, index) \
114 RUNTIME_ASSERT(args[index]->IsSmi()); \
115 PropertyDetails name = PropertyDetails(Smi::cast(args[index]));
116
117
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000118// Assert that the given argument has a valid value for a StrictModeFlag
119// and store it in a StrictModeFlag variable with the given name.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000120#define CONVERT_STRICT_MODE_ARG_CHECKED(name, index) \
121 RUNTIME_ASSERT(args[index]->IsSmi()); \
122 RUNTIME_ASSERT(args.smi_at(index) == kStrictMode || \
123 args.smi_at(index) == kNonStrictMode); \
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000124 StrictModeFlag name = \
125 static_cast<StrictModeFlag>(args.smi_at(index));
126
127
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000128// Assert that the given argument has a valid value for a LanguageMode
129// and store it in a LanguageMode variable with the given name.
130#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
131 ASSERT(args[index]->IsSmi()); \
132 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
133 args.smi_at(index) == STRICT_MODE || \
134 args.smi_at(index) == EXTENDED_MODE); \
135 LanguageMode name = \
136 static_cast<LanguageMode>(args.smi_at(index));
137
138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000139MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
140 JSObject* boilerplate) {
141 StackLimitCheck check(isolate);
142 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000143
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000144 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000145 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000146 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000147 if (!maybe_result->ToObject(&result)) return maybe_result;
148 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 JSObject* copy = JSObject::cast(result);
150
151 // Deep copy local properties.
152 if (copy->HasFastProperties()) {
153 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 for (int i = 0; i < properties->length(); i++) {
155 Object* value = properties->get(i);
156 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000157 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000158 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 if (!maybe_result->ToObject(&result)) return maybe_result;
160 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000161 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000162 }
163 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000164 int nof = copy->map()->inobject_properties();
165 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000166 Object* value = copy->InObjectPropertyAt(i);
167 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000168 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000169 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000170 if (!maybe_result->ToObject(&result)) return maybe_result;
171 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000172 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000173 }
174 }
175 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000176 { MaybeObject* maybe_result =
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000177 heap->AllocateFixedArray(copy->NumberOfLocalProperties());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000178 if (!maybe_result->ToObject(&result)) return maybe_result;
179 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000180 FixedArray* names = FixedArray::cast(result);
181 copy->GetLocalPropertyNames(names, 0);
182 for (int i = 0; i < names->length(); i++) {
183 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000184 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000185 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000186 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000187 // Only deep copy fields from the object literal expression.
188 // In particular, don't try to copy the length attribute of
189 // an array.
190 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000191 Object* value =
192 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000193 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000194 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000195 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000196 if (!maybe_result->ToObject(&result)) return maybe_result;
197 }
198 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000199 // Creating object copy for literals. No strict mode needed.
200 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000201 if (!maybe_result->ToObject(&result)) return maybe_result;
202 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000203 }
204 }
205 }
206
207 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000208 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000209 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000210 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000211 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000212 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000213 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000214 if (elements->map() == heap->fixed_cow_array_map()) {
215 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000216#ifdef DEBUG
217 for (int i = 0; i < elements->length(); i++) {
218 ASSERT(!elements->get(i)->IsJSObject());
219 }
220#endif
221 } else {
222 for (int i = 0; i < elements->length(); i++) {
223 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000224 ASSERT(value->IsSmi() ||
225 value->IsTheHole() ||
226 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000227 if (value->IsJSObject()) {
228 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000229 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
230 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000231 if (!maybe_result->ToObject(&result)) return maybe_result;
232 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000233 elements->set(i, result);
234 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000235 }
236 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000237 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000238 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000239 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000240 SeededNumberDictionary* element_dictionary = copy->element_dictionary();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000241 int capacity = element_dictionary->Capacity();
242 for (int i = 0; i < capacity; i++) {
243 Object* k = element_dictionary->KeyAt(i);
244 if (element_dictionary->IsKey(k)) {
245 Object* value = element_dictionary->ValueAt(i);
246 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000247 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000248 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
249 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000250 if (!maybe_result->ToObject(&result)) return maybe_result;
251 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000252 element_dictionary->ValueAtPut(i, result);
253 }
254 }
255 }
256 break;
257 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000258 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000259 UNIMPLEMENTED();
260 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000261 case EXTERNAL_PIXEL_ELEMENTS:
262 case EXTERNAL_BYTE_ELEMENTS:
263 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
264 case EXTERNAL_SHORT_ELEMENTS:
265 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
266 case EXTERNAL_INT_ELEMENTS:
267 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
268 case EXTERNAL_FLOAT_ELEMENTS:
269 case EXTERNAL_DOUBLE_ELEMENTS:
270 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000271 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000272 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000273 }
274 return copy;
275}
276
277
ager@chromium.org236ad962008-09-25 09:45:57 +0000278static Handle<Map> ComputeObjectLiteralMap(
279 Handle<Context> context,
280 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000281 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000282 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000283 int properties_length = constant_properties->length();
284 int number_of_properties = properties_length / 2;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000285 // Check that there are only symbols and array indices among keys.
286 int number_of_symbol_keys = 0;
287 for (int p = 0; p != properties_length; p += 2) {
288 Object* key = constant_properties->get(p);
289 uint32_t element_index = 0;
290 if (key->IsSymbol()) {
291 number_of_symbol_keys++;
292 } else if (key->ToArrayIndex(&element_index)) {
293 // An index key does not require space in the property backing store.
294 number_of_properties--;
295 } else {
296 // Bail out as a non-symbol non-index key makes caching impossible.
297 // ASSERT to make sure that the if condition after the loop is false.
298 ASSERT(number_of_symbol_keys != number_of_properties);
299 break;
ager@chromium.org236ad962008-09-25 09:45:57 +0000300 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000301 }
302 // If we only have symbols and array indices among keys then we can
303 // use the map cache in the global context.
304 const int kMaxKeys = 10;
305 if ((number_of_symbol_keys == number_of_properties) &&
306 (number_of_symbol_keys < kMaxKeys)) {
307 // Create the fixed array with the key.
308 Handle<FixedArray> keys =
309 isolate->factory()->NewFixedArray(number_of_symbol_keys);
310 if (number_of_symbol_keys > 0) {
311 int index = 0;
312 for (int p = 0; p < properties_length; p += 2) {
313 Object* key = constant_properties->get(p);
314 if (key->IsSymbol()) {
315 keys->set(index++, key);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000316 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000317 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000318 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000319 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000320 *is_result_from_cache = true;
321 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000322 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000323 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000325 Handle<Map>(context->object_function()->initial_map()),
326 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000327}
328
329
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000330static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000331 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000332 Handle<FixedArray> literals,
333 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000334
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000335
336static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000337 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000338 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000339 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000340 bool should_have_fast_elements,
341 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000342 // Get the global context from the literals array. This is the
343 // context in which the function was created and we use the object
344 // function from this context to create the object literal. We do
345 // not use the object function from the current global context
346 // because this might be the object function from another context
347 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000348 Handle<Context> context =
349 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000351 // In case we have function literals, we want the object to be in
352 // slow properties mode for now. We don't go in the map cache because
353 // maps with constant functions can't be shared if the functions are
354 // not the same (which is the common case).
355 bool is_result_from_cache = false;
356 Handle<Map> map = has_function_literal
357 ? Handle<Map>(context->object_function()->initial_map())
358 : ComputeObjectLiteralMap(context,
359 constant_properties,
360 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000362 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000363
364 // Normalize the elements of the boilerplate to save space if needed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000365 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000366
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000367 // Add the constant properties to the boilerplate.
368 int length = constant_properties->length();
369 bool should_transform =
370 !is_result_from_cache && boilerplate->HasFastProperties();
371 if (should_transform || has_function_literal) {
372 // Normalize the properties of object to avoid n^2 behavior
373 // when extending the object multiple properties. Indicate the number of
374 // properties to be added.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000375 JSObject::NormalizeProperties(
376 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000377 }
378
379 for (int index = 0; index < length; index +=2) {
380 Handle<Object> key(constant_properties->get(index+0), isolate);
381 Handle<Object> value(constant_properties->get(index+1), isolate);
382 if (value->IsFixedArray()) {
383 // The value contains the constant_properties of a
384 // simple object or array literal.
385 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
386 value = CreateLiteralBoilerplate(isolate, literals, array);
387 if (value.is_null()) return value;
388 }
389 Handle<Object> result;
390 uint32_t element_index = 0;
391 if (key->IsSymbol()) {
392 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
393 // Array index as string (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000394 result = JSObject::SetOwnElement(
395 boilerplate, element_index, value, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000396 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000397 Handle<String> name(String::cast(*key));
398 ASSERT(!name->AsArrayIndex(&element_index));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000399 result = JSObject::SetLocalPropertyIgnoreAttributes(
400 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000401 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000402 } else if (key->ToArrayIndex(&element_index)) {
403 // Array index (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000404 result = JSObject::SetOwnElement(
405 boilerplate, element_index, value, kNonStrictMode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000406 } else {
407 // Non-uint32 number.
408 ASSERT(key->IsNumber());
409 double num = key->Number();
410 char arr[100];
411 Vector<char> buffer(arr, ARRAY_SIZE(arr));
412 const char* str = DoubleToCString(num, buffer);
413 Handle<String> name =
414 isolate->factory()->NewStringFromAscii(CStrVector(str));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000415 result = JSObject::SetLocalPropertyIgnoreAttributes(
416 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000417 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 // If setting the property on the boilerplate throws an
419 // exception, the exception is converted to an empty handle in
420 // the handle based operations. In that case, we need to
421 // convert back to an exception.
422 if (result.is_null()) return result;
423 }
424
425 // Transform to fast properties if necessary. For object literals with
426 // containing function literals we defer this operation until after all
427 // computed properties have been assigned so that we can generate
428 // constant function properties.
429 if (should_transform && !has_function_literal) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000430 JSObject::TransformToFastProperties(
431 boilerplate, boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000432 }
433
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000434 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000435}
436
437
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000438MaybeObject* TransitionElements(Handle<Object> object,
439 ElementsKind to_kind,
440 Isolate* isolate) {
441 HandleScope scope(isolate);
442 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
443 ElementsKind from_kind =
444 Handle<JSObject>::cast(object)->map()->elements_kind();
445 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
446 Handle<Object> result = JSObject::TransitionElementsKind(
447 Handle<JSObject>::cast(object), to_kind);
448 if (result.is_null()) return isolate->ThrowIllegalOperation();
449 return *result;
450 }
451 return isolate->ThrowIllegalOperation();
452}
453
454
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000455static const int kSmiOnlyLiteralMinimumLength = 1024;
456
457
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000458Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000459 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000460 Handle<FixedArray> literals,
461 Handle<FixedArray> elements) {
462 // Create the JSArray.
463 Handle<JSFunction> constructor(
464 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000465 Handle<JSArray> object =
466 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000468 ElementsKind constant_elements_kind =
469 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
470 Handle<FixedArrayBase> constant_elements_values(
471 FixedArrayBase::cast(elements->get(1)));
472
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000473 Context* global_context = isolate->context()->global_context();
474 if (constant_elements_kind == FAST_SMI_ONLY_ELEMENTS) {
475 object->set_map(Map::cast(global_context->smi_js_array_map()));
476 } else if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
477 object->set_map(Map::cast(global_context->double_js_array_map()));
478 } else {
479 object->set_map(Map::cast(global_context->object_js_array_map()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000480 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000481
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000482 Handle<FixedArrayBase> copied_elements_values;
483 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
484 ASSERT(FLAG_smi_only_arrays);
485 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
486 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000487 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000488 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
489 constant_elements_kind == FAST_ELEMENTS);
490 const bool is_cow =
491 (constant_elements_values->map() ==
492 isolate->heap()->fixed_cow_array_map());
493 if (is_cow) {
494 copied_elements_values = constant_elements_values;
495#if DEBUG
496 Handle<FixedArray> fixed_array_values =
497 Handle<FixedArray>::cast(copied_elements_values);
498 for (int i = 0; i < fixed_array_values->length(); i++) {
499 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
500 }
501#endif
502 } else {
503 Handle<FixedArray> fixed_array_values =
504 Handle<FixedArray>::cast(constant_elements_values);
505 Handle<FixedArray> fixed_array_values_copy =
506 isolate->factory()->CopyFixedArray(fixed_array_values);
507 copied_elements_values = fixed_array_values_copy;
508 for (int i = 0; i < fixed_array_values->length(); i++) {
509 Object* current = fixed_array_values->get(i);
510 if (current->IsFixedArray()) {
511 // The value contains the constant_properties of a
512 // simple object or array literal.
513 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
514 Handle<Object> result =
515 CreateLiteralBoilerplate(isolate, literals, fa);
516 if (result.is_null()) return result;
517 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000518 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000519 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000520 }
521 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000522 object->set_elements(*copied_elements_values);
523 object->set_length(Smi::FromInt(copied_elements_values->length()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000524
525 // Ensure that the boilerplate object has FAST_ELEMENTS, unless the flag is
526 // on or the object is larger than the threshold.
527 if (!FLAG_smi_only_arrays &&
528 constant_elements_values->length() < kSmiOnlyLiteralMinimumLength) {
529 if (object->GetElementsKind() != FAST_ELEMENTS) {
530 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
531 }
532 }
533
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000534 return object;
535}
536
537
538static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000540 Handle<FixedArray> literals,
541 Handle<FixedArray> array) {
542 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000543 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000544 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000545 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 return CreateObjectLiteralBoilerplate(isolate,
547 literals,
548 elements,
549 true,
550 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000551 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000552 return CreateObjectLiteralBoilerplate(isolate,
553 literals,
554 elements,
555 false,
556 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000557 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000558 return Runtime::CreateArrayLiteralBoilerplate(
559 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000560 default:
561 UNREACHABLE();
562 return Handle<Object>::null();
563 }
564}
565
566
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000567RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000568 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000569 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000570 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000571 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000572 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000573 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000574 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
575 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000576
577 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000578 Handle<Object> boilerplate(literals->get(literals_index), isolate);
579 if (*boilerplate == isolate->heap()->undefined_value()) {
580 boilerplate = CreateObjectLiteralBoilerplate(isolate,
581 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000582 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 should_have_fast_elements,
584 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000585 if (boilerplate.is_null()) return Failure::Exception();
586 // Update the functions literal and return the boilerplate.
587 literals->set(literals_index, *boilerplate);
588 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000589 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000590}
591
592
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000593RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000594 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000595 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000596 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000597 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000598 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000599 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
601 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000602
603 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000604 Handle<Object> boilerplate(literals->get(literals_index), isolate);
605 if (*boilerplate == isolate->heap()->undefined_value()) {
606 boilerplate = CreateObjectLiteralBoilerplate(isolate,
607 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000608 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000609 should_have_fast_elements,
610 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000611 if (boilerplate.is_null()) return Failure::Exception();
612 // Update the functions literal and return the boilerplate.
613 literals->set(literals_index, *boilerplate);
614 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000615 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000616}
617
618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000619RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000620 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000621 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000622 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000623 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000624 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000625
626 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000627 Handle<Object> boilerplate(literals->get(literals_index), isolate);
628 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000629 boilerplate =
630 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000631 if (boilerplate.is_null()) return Failure::Exception();
632 // Update the functions literal and return the boilerplate.
633 literals->set(literals_index, *boilerplate);
634 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000635 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000636}
637
638
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000639RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000640 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000641 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000642 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000643 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000644 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000645
646 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 Handle<Object> boilerplate(literals->get(literals_index), isolate);
648 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000649 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000650 boilerplate =
651 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000652 if (boilerplate.is_null()) return Failure::Exception();
653 // Update the functions literal and return the boilerplate.
654 literals->set(literals_index, *boilerplate);
655 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000656 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000657 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000658 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000659 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000660 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000661}
662
663
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000664RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
665 ASSERT(args.length() == 2);
666 Object* handler = args[0];
667 Object* prototype = args[1];
668 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000669 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000670 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
671}
672
673
lrn@chromium.org34e60782011-09-15 07:25:40 +0000674RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
675 ASSERT(args.length() == 4);
676 Object* handler = args[0];
677 Object* call_trap = args[1];
678 Object* construct_trap = args[2];
679 Object* prototype = args[3];
680 Object* used_prototype =
681 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
682 return isolate->heap()->AllocateJSFunctionProxy(
683 handler, call_trap, construct_trap, used_prototype);
684}
685
686
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000687RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
688 ASSERT(args.length() == 1);
689 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000690 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000691}
692
693
lrn@chromium.org34e60782011-09-15 07:25:40 +0000694RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
695 ASSERT(args.length() == 1);
696 Object* obj = args[0];
697 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
698}
699
700
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000701RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
702 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000703 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000704 return proxy->handler();
705}
706
707
lrn@chromium.org34e60782011-09-15 07:25:40 +0000708RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
709 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000710 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000711 return proxy->call_trap();
712}
713
714
715RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
716 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000717 CONVERT_ARG_CHECKED(JSFunctionProxy, proxy, 0);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000718 return proxy->construct_trap();
719}
720
721
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000722RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
723 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000724 CONVERT_ARG_CHECKED(JSProxy, proxy, 0);
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000725 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000726 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000727}
728
729
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000730RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
731 HandleScope scope(isolate);
732 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000733 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000734 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
735 holder->set_table(*table);
736 return *holder;
737}
738
739
740RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
741 HandleScope scope(isolate);
742 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000743 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000744 Handle<Object> key(args[1]);
745 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
746 table = ObjectHashSetAdd(table, key);
747 holder->set_table(*table);
748 return isolate->heap()->undefined_symbol();
749}
750
751
752RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
753 HandleScope scope(isolate);
754 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000755 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000756 Handle<Object> key(args[1]);
757 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
758 return isolate->heap()->ToBoolean(table->Contains(*key));
759}
760
761
762RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
763 HandleScope scope(isolate);
764 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000765 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000766 Handle<Object> key(args[1]);
767 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
768 table = ObjectHashSetRemove(table, key);
769 holder->set_table(*table);
770 return isolate->heap()->undefined_symbol();
771}
772
773
774RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
775 HandleScope scope(isolate);
776 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000777 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000778 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
779 holder->set_table(*table);
780 return *holder;
781}
782
783
784RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
785 HandleScope scope(isolate);
786 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000787 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000788 Handle<Object> key(args[1]);
789 return ObjectHashTable::cast(holder->table())->Lookup(*key);
790}
791
792
793RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
794 HandleScope scope(isolate);
795 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000796 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000797 Handle<Object> key(args[1]);
798 Handle<Object> value(args[2]);
799 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
800 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
801 holder->set_table(*new_table);
802 return *value;
803}
804
805
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000806RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
807 HandleScope scope(isolate);
808 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000809 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000810 ASSERT(weakmap->map()->inobject_properties() == 0);
811 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
812 weakmap->set_table(*table);
813 weakmap->set_next(Smi::FromInt(0));
814 return *weakmap;
815}
816
817
818RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
819 NoHandleAllocation ha;
820 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000821 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
822 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000823 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000824}
825
826
827RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
828 HandleScope scope(isolate);
829 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000830 CONVERT_ARG_HANDLE_CHECKED(JSWeakMap, weakmap, 0);
831 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000832 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000833 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000834 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
835 weakmap->set_table(*new_table);
836 return *value;
837}
838
839
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000840RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000841 NoHandleAllocation ha;
842 ASSERT(args.length() == 1);
843 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000844 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000845 return JSObject::cast(obj)->class_name();
846}
847
ager@chromium.org7c537e22008-10-16 08:43:32 +0000848
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000849RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
850 NoHandleAllocation ha;
851 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +0000852 CONVERT_ARG_CHECKED(JSReceiver, input_obj, 0);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000853 Object* obj = input_obj;
854 // We don't expect access checks to be needed on JSProxy objects.
855 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000856 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000857 if (obj->IsAccessCheckNeeded() &&
858 !isolate->MayNamedAccess(JSObject::cast(obj),
859 isolate->heap()->Proto_symbol(),
860 v8::ACCESS_GET)) {
861 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
862 return isolate->heap()->undefined_value();
863 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000864 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000865 } while (obj->IsJSObject() &&
866 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000867 return obj;
868}
869
870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000871RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000872 NoHandleAllocation ha;
873 ASSERT(args.length() == 2);
874 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
875 Object* O = args[0];
876 Object* V = args[1];
877 while (true) {
878 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000879 if (prototype->IsNull()) return isolate->heap()->false_value();
880 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000881 V = prototype;
882 }
883}
884
885
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000886// Recursively traverses hidden prototypes if property is not found
887static void GetOwnPropertyImplementation(JSObject* obj,
888 String* name,
889 LookupResult* result) {
890 obj->LocalLookupRealNamedProperty(name, result);
891
892 if (!result->IsProperty()) {
893 Object* proto = obj->GetPrototype();
894 if (proto->IsJSObject() &&
895 JSObject::cast(proto)->map()->is_hidden_prototype())
896 GetOwnPropertyImplementation(JSObject::cast(proto),
897 name, result);
898 }
899}
900
901
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000902static bool CheckAccessException(LookupResult* result,
903 v8::AccessType access_type) {
904 if (result->type() == CALLBACKS) {
905 Object* callback = result->GetCallbackObject();
906 if (callback->IsAccessorInfo()) {
907 AccessorInfo* info = AccessorInfo::cast(callback);
908 bool can_access =
909 (access_type == v8::ACCESS_HAS &&
910 (info->all_can_read() || info->all_can_write())) ||
911 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
912 (access_type == v8::ACCESS_SET && info->all_can_write());
913 return can_access;
914 }
915 }
916
917 return false;
918}
919
920
921static bool CheckAccess(JSObject* obj,
922 String* name,
923 LookupResult* result,
924 v8::AccessType access_type) {
925 ASSERT(result->IsProperty());
926
927 JSObject* holder = result->holder();
928 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000929 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000930 while (true) {
931 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000932 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000933 // Access check callback denied the access, but some properties
934 // can have a special permissions which override callbacks descision
935 // (currently see v8::AccessControl).
936 break;
937 }
938
939 if (current == holder) {
940 return true;
941 }
942
943 current = JSObject::cast(current->GetPrototype());
944 }
945
946 // API callbacks can have per callback access exceptions.
947 switch (result->type()) {
948 case CALLBACKS: {
949 if (CheckAccessException(result, access_type)) {
950 return true;
951 }
952 break;
953 }
954 case INTERCEPTOR: {
955 // If the object has an interceptor, try real named properties.
956 // Overwrite the result to fetch the correct property later.
957 holder->LookupRealNamedProperty(name, result);
958 if (result->IsProperty()) {
959 if (CheckAccessException(result, access_type)) {
960 return true;
961 }
962 }
963 break;
964 }
965 default:
966 break;
967 }
968
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000969 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000970 return false;
971}
972
973
974// TODO(1095): we should traverse hidden prototype hierachy as well.
975static bool CheckElementAccess(JSObject* obj,
976 uint32_t index,
977 v8::AccessType access_type) {
978 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000979 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000980 return false;
981 }
982
983 return true;
984}
985
986
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000987// Enumerator used as indices into the array returned from GetOwnProperty
988enum PropertyDescriptorIndices {
989 IS_ACCESSOR_INDEX,
990 VALUE_INDEX,
991 GETTER_INDEX,
992 SETTER_INDEX,
993 WRITABLE_INDEX,
994 ENUMERABLE_INDEX,
995 CONFIGURABLE_INDEX,
996 DESCRIPTOR_SIZE
997};
998
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000999
1000static MaybeObject* GetOwnProperty(Isolate* isolate,
1001 Handle<JSObject> obj,
1002 Handle<String> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001003 Heap* heap = isolate->heap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001004 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1005 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001006 LookupResult result(isolate);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001007 // This could be an element.
1008 uint32_t index;
1009 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001010 switch (obj->HasLocalElement(index)) {
1011 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001012 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001013
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001014 case JSObject::STRING_CHARACTER_ELEMENT: {
1015 // Special handling of string objects according to ECMAScript 5
1016 // 15.5.5.2. Note that this might be a string object with elements
1017 // other than the actual string value. This is covered by the
1018 // subsequent cases.
1019 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1020 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001021 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001022
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001023 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001024 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001025 elms->set(WRITABLE_INDEX, heap->false_value());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00001026 elms->set(ENUMERABLE_INDEX, heap->true_value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001027 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001028 return *desc;
1029 }
1030
1031 case JSObject::INTERCEPTED_ELEMENT:
1032 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001033 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001034 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001035 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001036 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001037 elms->set(WRITABLE_INDEX, heap->true_value());
1038 elms->set(ENUMERABLE_INDEX, heap->true_value());
1039 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001040 return *desc;
1041 }
1042
1043 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001044 Handle<JSObject> holder = obj;
1045 if (obj->IsJSGlobalProxy()) {
1046 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001047 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001048 ASSERT(proto->IsJSGlobalObject());
1049 holder = Handle<JSObject>(JSObject::cast(proto));
1050 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001051 FixedArray* elements = FixedArray::cast(holder->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001052 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001053 if (elements->map() == heap->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001054 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001055 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001056 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001057 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001058 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001059 ASSERT(entry != SeededNumberDictionary::kNotFound);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001060 PropertyDetails details = dictionary->DetailsAt(entry);
1061 switch (details.type()) {
1062 case CALLBACKS: {
1063 // This is an accessor property with getter and/or setter.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001064 AccessorPair* accessors =
1065 AccessorPair::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001066 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001067 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00001068 elms->set(GETTER_INDEX, accessors->GetComponent(ACCESSOR_GETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001069 }
1070 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00001071 elms->set(SETTER_INDEX, accessors->GetComponent(ACCESSOR_SETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001072 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001073 break;
1074 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001075 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001076 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001077 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001078 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001079 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001080 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001081 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001082 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001083 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001084 default:
1085 UNREACHABLE();
1086 break;
1087 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001088 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1089 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001090 return *desc;
1091 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001092 }
1093 }
1094
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001095 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001096 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001097
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001098 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001099 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001100 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001101
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001102 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001103 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001104 }
1105
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001106 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1107 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001108
1109 bool is_js_accessor = (result.type() == CALLBACKS) &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001110 (result.GetCallbackObject()->IsAccessorPair());
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001111
1112 if (is_js_accessor) {
1113 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001114 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001115
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001116 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001117 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00001118 elms->set(GETTER_INDEX, accessors->GetComponent(ACCESSOR_GETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001119 }
1120 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00001121 elms->set(SETTER_INDEX, accessors->GetComponent(ACCESSOR_SETTER));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001122 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001123 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001124 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1125 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001126
1127 PropertyAttributes attrs;
1128 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001129 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001130 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1131 if (!maybe_value->ToObject(&value)) return maybe_value;
1132 }
1133 elms->set(VALUE_INDEX, value);
1134 }
1135
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001136 return *desc;
1137}
1138
1139
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001140// Returns an array with the property description:
1141// if args[1] is not a property on args[0]
1142// returns undefined
1143// if args[1] is a data property on args[0]
1144// [false, value, Writeable, Enumerable, Configurable]
1145// if args[1] is an accessor on args[0]
1146// [true, GetFunction, SetFunction, Enumerable, Configurable]
1147RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
1148 ASSERT(args.length() == 2);
1149 HandleScope scope(isolate);
1150 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1151 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
1152 return GetOwnProperty(isolate, obj, name);
1153}
1154
1155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001156RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001157 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001158 CONVERT_ARG_CHECKED(JSObject, obj, 0);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001159 return obj->PreventExtensions();
1160}
1161
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001163RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001164 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001165 CONVERT_ARG_CHECKED(JSObject, obj, 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001166 if (obj->IsJSGlobalProxy()) {
1167 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001168 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001169 ASSERT(proto->IsJSGlobalObject());
1170 obj = JSObject::cast(proto);
1171 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001172 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001173}
1174
1175
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001176RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001177 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001178 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001179 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, re, 0);
1180 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
1181 CONVERT_ARG_HANDLE_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001182 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1183 if (result.is_null()) return Failure::Exception();
1184 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185}
1186
1187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001188RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001189 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001190 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001191 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001192 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193}
1194
1195
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001196RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001197 ASSERT(args.length() == 1);
1198 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001199 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001200 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001201}
1202
1203
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001204RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001206 CONVERT_ARG_CHECKED(HeapObject, templ, 0);
1207 CONVERT_SMI_ARG_CHECKED(index, 1)
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001208 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1209 InstanceType type = templ->map()->instance_type();
1210 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1211 type == OBJECT_TEMPLATE_INFO_TYPE);
1212 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001213 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001214 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1215 } else {
1216 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1217 }
1218 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219}
1220
1221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001222RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001223 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001224 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001225 Map* old_map = object->map();
1226 bool needs_access_checks = old_map->is_access_check_needed();
1227 if (needs_access_checks) {
1228 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001229 Object* new_map;
1230 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1231 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1232 }
ager@chromium.org32912102009-01-16 10:38:43 +00001233
1234 Map::cast(new_map)->set_is_access_check_needed(false);
1235 object->set_map(Map::cast(new_map));
1236 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001237 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001238}
1239
1240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001241RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001242 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001243 CONVERT_ARG_CHECKED(HeapObject, object, 0);
ager@chromium.org32912102009-01-16 10:38:43 +00001244 Map* old_map = object->map();
1245 if (!old_map->is_access_check_needed()) {
1246 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001247 Object* new_map;
1248 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1249 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1250 }
ager@chromium.org32912102009-01-16 10:38:43 +00001251
1252 Map::cast(new_map)->set_is_access_check_needed(true);
1253 object->set_map(Map::cast(new_map));
1254 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001255 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001256}
1257
1258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001259static Failure* ThrowRedeclarationError(Isolate* isolate,
1260 const char* type,
1261 Handle<String> name) {
1262 HandleScope scope(isolate);
1263 Handle<Object> type_handle =
1264 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265 Handle<Object> args[2] = { type_handle, name };
1266 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001267 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1268 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269}
1270
1271
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001272RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001273 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001274 HandleScope scope(isolate);
1275 Handle<GlobalObject> global = Handle<GlobalObject>(
1276 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277
ager@chromium.org3811b432009-10-28 14:53:37 +00001278 Handle<Context> context = args.at<Context>(0);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001279 CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001280 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282 // Traverse the name/value pairs and set the properties.
1283 int length = pairs->length();
1284 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001285 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001287 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001288
1289 // We have to declare a global const property. To capture we only
1290 // assign to it when evaluating the assignment for "const x =
1291 // <expr>" the initial value is the hole.
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
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001340 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1341
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001342 // Safari does not allow the invocation of callback setters for
1343 // function declarations. To mimic this behavior, we do not allow
1344 // the invocation of setters for function values. This makes a
1345 // difference for global functions with the same names as event
1346 // handlers such as "function onload() {}". Firefox does call the
1347 // onload setter in those case and Safari does not. We follow
1348 // Safari for compatibility.
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001349 if (is_function_declaration) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001350 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001351 // Do not overwrite READ_ONLY properties.
1352 if (lookup.GetAttributes() & READ_ONLY) {
1353 if (language_mode != CLASSIC_MODE) {
1354 Handle<Object> args[] = { name };
1355 return isolate->Throw(*isolate->factory()->NewTypeError(
1356 "strict_cannot_assign", HandleVector(args, ARRAY_SIZE(args))));
1357 }
1358 continue;
1359 }
1360 // Do not change DONT_DELETE to false from true.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001361 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001362 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001363 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1364
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001365 RETURN_IF_EMPTY_HANDLE(
1366 isolate,
1367 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
1368 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001369 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001370 RETURN_IF_EMPTY_HANDLE(
1371 isolate,
1372 JSReceiver::SetProperty(global, name, value,
1373 static_cast<PropertyAttributes>(attr),
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001374 language_mode == CLASSIC_MODE
1375 ? kNonStrictMode : kStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376 }
1377 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001378
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001379 ASSERT(!isolate->has_pending_exception());
1380 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001381}
1382
1383
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001384RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001385 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001386 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001387
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001388 // Declarations are always made in a function or global context. In the
1389 // case of eval code, the context passed is the context of the caller,
1390 // which may be some nested context and not the declaration context.
1391 RUNTIME_ASSERT(args[0]->IsContext());
1392 Handle<Context> context(Context::cast(args[0])->declaration_context());
1393
ager@chromium.org7c537e22008-10-16 08:43:32 +00001394 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001395 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001396 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001397 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001398
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 int index;
1400 PropertyAttributes attributes;
1401 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001402 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001403 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001404 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001405
1406 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001407 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001408 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1409 // Functions are not read-only.
1410 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1411 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001412 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413 }
1414
1415 // Initialize it if necessary.
1416 if (*initial_value != NULL) {
1417 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001418 ASSERT(holder.is_identical_to(context));
1419 if (((attributes & READ_ONLY) == 0) ||
1420 context->get(index)->IsTheHole()) {
1421 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422 }
1423 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001424 // Slow case: The property is in the context extension object of a
1425 // function context or the global object of a global context.
1426 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001427 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001428 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001429 JSReceiver::SetProperty(object, name, initial_value, mode,
1430 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001431 }
1432 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001433
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001434 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001435 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001436 // "declared" in the function context's extension context or as a
1437 // property of the the global object.
1438 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001439 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001440 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001441 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001442 // Context extension objects are allocated lazily.
1443 ASSERT(context->IsFunctionContext());
1444 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001445 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001446 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001447 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001448 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001449
ager@chromium.org7c537e22008-10-16 08:43:32 +00001450 // Declare the property by setting it to the initial value if provided,
1451 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1452 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001453 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001454 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001455 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001456 // Declaring a const context slot is a conflicting declaration if
1457 // there is a callback with that name in a prototype. It is
1458 // allowed to introduce const variables in
1459 // JSContextExtensionObjects. They are treated specially in
1460 // SetProperty and no setters are invoked for those since they are
1461 // not real JSObjects.
1462 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001463 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001464 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001465 object->Lookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001466 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001467 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001468 }
1469 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001470 RETURN_IF_EMPTY_HANDLE(
1471 isolate,
1472 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001473 }
1474
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001475 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001476}
1477
1478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001479RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001480 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001481 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001482 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001483 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001484
1485 // Determine if we need to assign to the variable if it already
1486 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001487 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1488 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001489
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001490 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001491 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001492 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001493 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1494 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1495 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001496
1497 // According to ECMA-262, section 12.2, page 62, the property must
1498 // not be deletable.
1499 PropertyAttributes attributes = DONT_DELETE;
1500
1501 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001502 // there, there is a property with this name in the prototype chain.
1503 // We follow Safari and Firefox behavior and only set the property
1504 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001505 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001506 // Note that objects can have hidden prototypes, so we need to traverse
1507 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001508 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001509 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001510 while (object->IsJSObject() &&
1511 JSObject::cast(object)->map()->is_hidden_prototype()) {
1512 JSObject* raw_holder = JSObject::cast(object);
1513 raw_holder->LocalLookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001514 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001515 HandleScope handle_scope(isolate);
1516 Handle<JSObject> holder(raw_holder);
1517 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1518 // Update the raw pointer in case it's changed due to GC.
1519 raw_holder = *holder;
1520 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1521 // Found an interceptor that's not read only.
1522 if (assign) {
1523 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001524 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001525 } else {
1526 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001527 }
1528 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001529 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001530 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001531 }
1532
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001533 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001534 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001535 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001536 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001537 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001538 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001539}
1540
1541
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001542RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 // All constants are declared with an initial value. The name
1544 // of the constant is the first argument and the initial value
1545 // is the second.
1546 RUNTIME_ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001547 CONVERT_ARG_HANDLE_CHECKED(String, name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001548 Handle<Object> value = args.at<Object>(1);
1549
1550 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001551 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001552
1553 // According to ECMA-262, section 12.2, page 62, the property must
1554 // not be deletable. Since it's a const, it must be READ_ONLY too.
1555 PropertyAttributes attributes =
1556 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1557
1558 // Lookup the property locally in the global object. If it isn't
1559 // there, we add the property and take special precautions to always
1560 // add it as a local property even in case of callbacks in the
1561 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001562 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001563 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564 global->LocalLookup(*name, &lookup);
1565 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001566 return global->SetLocalPropertyIgnoreAttributes(*name,
1567 *value,
1568 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001569 }
1570
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001571 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001572 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001573 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001574 HandleScope handle_scope(isolate);
1575 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001576
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001577 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001578 // property through an interceptor and only do it if it's
1579 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001580 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001581 RETURN_IF_EMPTY_HANDLE(
1582 isolate,
1583 JSReceiver::SetProperty(global, name, value, attributes,
1584 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001585 return *value;
1586 }
1587
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001588 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001589 // constant. For now, we determine this by checking if the
1590 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001591 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001592 PropertyType type = lookup.type();
1593 if (type == FIELD) {
1594 FixedArray* properties = global->properties();
1595 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001596 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001597 properties->set(index, *value);
1598 }
1599 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001600 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1601 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001602 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001603 }
1604 } else {
1605 // Ignore re-initialization of constants that have already been
1606 // assigned a function value.
1607 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1608 }
1609
1610 // Use the set value as the result of the operation.
1611 return *value;
1612}
1613
1614
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001615RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001616 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001617 ASSERT(args.length() == 3);
1618
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001619 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001620 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001621
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001622 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001623 RUNTIME_ASSERT(args[1]->IsContext());
1624 Handle<Context> context(Context::cast(args[1])->declaration_context());
1625
1626 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001627
1628 int index;
1629 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001630 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001631 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001632 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001633 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001634
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001635 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001636 ASSERT(holder->IsContext());
1637 // Property was found in a context. Perform the assignment if we
1638 // found some non-constant or an uninitialized constant.
1639 Handle<Context> context = Handle<Context>::cast(holder);
1640 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1641 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001642 }
1643 return *value;
1644 }
1645
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001646 // The property could not be found, we introduce it as a property of the
1647 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001648 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001649 Handle<JSObject> global = Handle<JSObject>(
1650 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001651 // Strict mode not needed (const disallowed in strict mode).
1652 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001653 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001654 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001655 return *value;
1656 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001657
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001658 // The property was present in some function's context extension object,
1659 // as a property on the subject of a with, or as a property of the global
1660 // object.
1661 //
1662 // In most situations, eval-introduced consts should still be present in
1663 // the context extension object. However, because declaration and
1664 // initialization are separate, the property might have been deleted
1665 // before we reach the initialization point.
1666 //
1667 // Example:
1668 //
1669 // function f() { eval("delete x; const x;"); }
1670 //
1671 // In that case, the initialization behaves like a normal assignment.
1672 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001673
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001674 if (*object == context->extension()) {
1675 // This is the property that was introduced by the const declaration.
1676 // Set it if it hasn't been set before. NOTE: We cannot use
1677 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001678 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001679 object->LocalLookupRealNamedProperty(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001680 ASSERT(lookup.IsFound()); // the property was declared
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001681 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1682
1683 PropertyType type = lookup.type();
1684 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001685 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001686 int index = lookup.GetFieldIndex();
1687 if (properties->get(index)->IsTheHole()) {
1688 properties->set(index, *value);
1689 }
1690 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001691 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1692 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001693 }
1694 } else {
1695 // We should not reach here. Any real, named property should be
1696 // either a field or a dictionary slot.
1697 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001698 }
1699 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001700 // The property was found on some other object. Set it if it is not a
1701 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001702 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001703 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001704 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001705 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001706 JSReceiver::SetProperty(object, name, value, attributes,
1707 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001708 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001709 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001710
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001711 return *value;
1712}
1713
1714
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001715RUNTIME_FUNCTION(MaybeObject*,
1716 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001717 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001718 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001719 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001720 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001721 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001722 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001723 }
1724 return *object;
1725}
1726
1727
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001728RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001729 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001730 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001731 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
1732 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001733 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001734 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001735 CONVERT_SMI_ARG_CHECKED(index, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001736 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001737 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001738 RUNTIME_ASSERT(index >= 0);
1739 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001740 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001741 Handle<Object> result = RegExpImpl::Exec(regexp,
1742 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001743 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001744 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001745 if (result.is_null()) return Failure::Exception();
1746 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001747}
1748
1749
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001750RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001751 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001752 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001753 if (elements_count < 0 ||
1754 elements_count > FixedArray::kMaxLength ||
1755 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001756 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001757 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001758 Object* new_object;
1759 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001760 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001761 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1762 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001763 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001764 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1765 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001766 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1767 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001768 {
1769 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001770 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001771 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001772 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001773 }
1774 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001775 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001776 array->set_elements(elements);
1777 array->set_length(Smi::FromInt(elements_count));
1778 // Write in-object properties after the length of the array.
1779 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1780 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1781 return array;
1782}
1783
1784
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001785RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001786 AssertNoAllocation no_alloc;
1787 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001788 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1789 CONVERT_ARG_CHECKED(String, source, 1);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001790
1791 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001792 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001793
1794 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001795 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001796
1797 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001799
1800 Map* map = regexp->map();
1801 Object* constructor = map->constructor();
1802 if (constructor->IsJSFunction() &&
1803 JSFunction::cast(constructor)->initial_map() == map) {
1804 // If we still have the original map, set in-object properties directly.
1805 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001806 // Both true and false are immovable immortal objects so no need for write
1807 // barrier.
1808 regexp->InObjectPropertyAtPut(
1809 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1810 regexp->InObjectPropertyAtPut(
1811 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1812 regexp->InObjectPropertyAtPut(
1813 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001814 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1815 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001816 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001817 return regexp;
1818 }
1819
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001820 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001821 PropertyAttributes final =
1822 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1823 PropertyAttributes writable =
1824 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001825 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001826 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001827 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001828 source,
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->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001832 global,
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->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001837 ignoreCase,
1838 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001839 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001840 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001841 multiline,
1842 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001843 ASSERT(!result->IsFailure());
1844 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001845 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001846 Smi::FromInt(0),
1847 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001848 ASSERT(!result->IsFailure());
1849 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001850 return regexp;
1851}
1852
1853
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001854RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001855 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001856 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001857 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001858 // This is necessary to enable fast checks for absence of elements
1859 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001860 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001861 return Smi::FromInt(0);
1862}
1863
1864
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001865static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1866 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001867 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001868 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001869 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1870 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1871 Handle<JSFunction> optimized =
1872 isolate->factory()->NewFunction(key,
1873 JS_OBJECT_TYPE,
1874 JSObject::kHeaderSize,
1875 code,
1876 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001877 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001878 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001879 return optimized;
1880}
1881
1882
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001883RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001884 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001885 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001886 CONVERT_ARG_HANDLE_CHECKED(JSObject, holder, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001887
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001888 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1889 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1890 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1891 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1892 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1893 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1894 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001895
1896 return *holder;
1897}
1898
1899
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001900RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001901 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001902 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001903
1904 if (!callable->IsJSFunction()) {
1905 HandleScope scope(isolate);
1906 bool threw = false;
1907 Handle<Object> delegate =
1908 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
1909 if (threw) return Failure::Exception();
1910 callable = JSFunction::cast(*delegate);
1911 }
1912 JSFunction* function = JSFunction::cast(callable);
1913
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001914 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001915 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001916 return isolate->heap()->undefined_value();
1917 }
1918 // Returns undefined for strict or native functions, or
1919 // the associated global receiver for "normal" functions.
1920
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001921 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001922 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001923 return global_context->global()->global_receiver();
1924}
1925
1926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001927RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001928 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001929 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001930 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001931 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001932 Handle<String> pattern = args.at<String>(2);
1933 Handle<String> flags = args.at<String>(3);
1934
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001935 // Get the RegExp function from the context in the literals array.
1936 // This is the RegExp function from the context in which the
1937 // function was created. We do not use the RegExp function from the
1938 // current global context because this might be the RegExp function
1939 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001940 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001941 Handle<JSFunction>(
1942 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001943 // Compute the regular expression literal.
1944 bool has_pending_exception;
1945 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001946 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1947 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001948 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001949 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001950 return Failure::Exception();
1951 }
1952 literals->set(index, *regexp);
1953 return *regexp;
1954}
1955
1956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001957RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001958 NoHandleAllocation ha;
1959 ASSERT(args.length() == 1);
1960
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001961 CONVERT_ARG_CHECKED(JSFunction, f, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001962 return f->shared()->name();
1963}
1964
1965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001966RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001967 NoHandleAllocation ha;
1968 ASSERT(args.length() == 2);
1969
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001970 CONVERT_ARG_CHECKED(JSFunction, f, 0);
1971 CONVERT_ARG_CHECKED(String, name, 1);
ager@chromium.org236ad962008-09-25 09:45:57 +00001972 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001973 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001974}
1975
1976
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001977RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
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 return isolate->heap()->ToBoolean(
1982 f->shared()->name_should_print_as_anonymous());
1983}
1984
1985
1986RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1987 NoHandleAllocation ha;
1988 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001989 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001990 f->shared()->set_name_should_print_as_anonymous(true);
1991 return isolate->heap()->undefined_value();
1992}
1993
1994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001995RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001996 NoHandleAllocation ha;
1997 ASSERT(args.length() == 1);
1998
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00001999 CONVERT_ARG_CHECKED(JSFunction, f, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002000 Object* obj = f->RemovePrototype();
2001 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002002
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002003 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002004}
2005
2006
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002007RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002008 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002009 ASSERT(args.length() == 1);
2010
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002011 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002012 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2013 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002014
2015 return *GetScriptWrapper(Handle<Script>::cast(script));
2016}
2017
2018
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002019RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002020 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002021 ASSERT(args.length() == 1);
2022
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002023 CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0);
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002024 Handle<SharedFunctionInfo> shared(f->shared());
2025 return *shared->GetSourceCode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002026}
2027
2028
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002029RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002030 NoHandleAllocation ha;
2031 ASSERT(args.length() == 1);
2032
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002033 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002034 int pos = fun->shared()->start_position();
2035 return Smi::FromInt(pos);
2036}
2037
2038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002039RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002040 ASSERT(args.length() == 2);
2041
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002042 CONVERT_ARG_CHECKED(Code, code, 0);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002043 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2044
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002045 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2046
2047 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002048 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002049}
2050
2051
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002052RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002053 NoHandleAllocation ha;
2054 ASSERT(args.length() == 2);
2055
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002056 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2057 CONVERT_ARG_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002058 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002059 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002060}
2061
2062
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002063RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002064 NoHandleAllocation ha;
2065 ASSERT(args.length() == 2);
2066
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002067 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
2068 CONVERT_SMI_ARG_CHECKED(length, 1);
2069 fun->shared()->set_length(length);
2070 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002071}
2072
2073
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002074RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002075 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002076 ASSERT(args.length() == 2);
2077
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002078 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002079 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002080 Object* obj;
2081 { MaybeObject* maybe_obj =
2082 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2083 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2084 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002085 return args[0]; // return TOS
2086}
2087
2088
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002089RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2090 NoHandleAllocation ha;
2091 RUNTIME_ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002092 CONVERT_ARG_CHECKED(JSFunction, function, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002093
2094 MaybeObject* maybe_name =
2095 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2096 String* name;
2097 if (!maybe_name->To(&name)) return maybe_name;
2098
2099 if (function->HasFastProperties()) {
2100 // Construct a new field descriptor with updated attributes.
2101 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2102 int index = instance_desc->Search(name);
2103 ASSERT(index != DescriptorArray::kNotFound);
2104 PropertyDetails details(instance_desc->GetDetails(index));
2105 CallbacksDescriptor new_desc(name,
2106 instance_desc->GetValue(index),
2107 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2108 details.index());
2109 // Construct a new field descriptors array containing the new descriptor.
2110 Object* descriptors_unchecked;
2111 { MaybeObject* maybe_descriptors_unchecked =
2112 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2113 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2114 return maybe_descriptors_unchecked;
2115 }
2116 }
2117 DescriptorArray* new_descriptors =
2118 DescriptorArray::cast(descriptors_unchecked);
2119 // Create a new map featuring the new field descriptors array.
2120 Object* map_unchecked;
2121 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2122 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2123 return maybe_map_unchecked;
2124 }
2125 }
2126 Map* new_map = Map::cast(map_unchecked);
2127 new_map->set_instance_descriptors(new_descriptors);
2128 function->set_map(new_map);
2129 } else { // Dictionary properties.
2130 // Directly manipulate the property details.
2131 int entry = function->property_dictionary()->FindEntry(name);
2132 ASSERT(entry != StringDictionary::kNotFound);
2133 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2134 PropertyDetails new_details(
2135 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2136 details.type(),
2137 details.index());
2138 function->property_dictionary()->DetailsAtPut(entry, new_details);
2139 }
2140 return function;
2141}
2142
2143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002144RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +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->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002150}
2151
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002153RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002154 NoHandleAllocation ha;
2155 ASSERT(args.length() == 1);
2156
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002157 CONVERT_ARG_CHECKED(JSFunction, f, 0);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002158 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002159}
2160
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002161
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002162RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002163 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002164 ASSERT(args.length() == 2);
2165
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002166 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002167 Handle<Object> code = args.at<Object>(1);
2168
2169 Handle<Context> context(target->context());
2170
2171 if (!code->IsNull()) {
2172 RUNTIME_ASSERT(code->IsJSFunction());
2173 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002174 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002175
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002176 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002177 return Failure::Exception();
2178 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002179 // Since we don't store the source for this we should never
2180 // optimize this.
2181 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002182 // Set the code, scope info, formal parameter count,
2183 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002184 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002185 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002186 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002187 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002188 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002189 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002190 // Set the source code of the target function to undefined.
2191 // SetCode is only used for built-in constructors like String,
2192 // Array, and Object, and some web code
2193 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002194 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002195 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002196 // Clear the optimization hints related to the compiled code as these are no
2197 // longer valid when the code is overwritten.
2198 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002199 context = Handle<Context>(fun->context());
2200
2201 // Make sure we get a fresh copy of the literal vector to avoid
2202 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002203 int number_of_literals = fun->NumberOfLiterals();
2204 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002205 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002206 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002207 // Insert the object, regexp and array functions in the literals
2208 // array prefix. These are the functions that will be used when
2209 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002210 literals->set(JSFunction::kLiteralGlobalContextIndex,
2211 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002212 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002213 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002214 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002215
2216 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2217 isolate->logger()->LogExistingFunction(
2218 shared, Handle<Code>(shared->code()));
2219 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002220 }
2221
2222 target->set_context(*context);
2223 return *target;
2224}
2225
2226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002227RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002228 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002229 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002230 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002231 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002232 RUNTIME_ASSERT(num >= 0);
2233 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002234 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002235}
2236
2237
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002238MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2239 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002240 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002241 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002242 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002243 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002244 }
2245 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002246 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002247}
2248
2249
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002250RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002251 NoHandleAllocation ha;
2252 ASSERT(args.length() == 2);
2253
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00002254 CONVERT_ARG_CHECKED(String, subject, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002255 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002256 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002257
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002258 uint32_t i = 0;
2259 if (index->IsSmi()) {
2260 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002261 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002262 i = value;
2263 } else {
2264 ASSERT(index->IsHeapNumber());
2265 double value = HeapNumber::cast(index)->value();
2266 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002267 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002268
2269 // Flatten the string. If someone wants to get a char at an index
2270 // in a cons string, it is likely that more indices will be
2271 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002272 Object* flat;
2273 { MaybeObject* maybe_flat = subject->TryFlatten();
2274 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2275 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002276 subject = String::cast(flat);
2277
2278 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002279 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002280 }
2281
2282 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002283}
2284
2285
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002286RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002287 NoHandleAllocation ha;
2288 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002289 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002290}
2291
lrn@chromium.org25156de2010-04-06 13:10:27 +00002292
2293class FixedArrayBuilder {
2294 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002295 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2296 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
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(initial_capacity > 0);
2302 }
2303
2304 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2305 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002306 length_(0),
2307 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002308 // Require a non-zero initial size. Ensures that doubling the size to
2309 // extend the array will work.
2310 ASSERT(backing_store->length() > 0);
2311 }
2312
2313 bool HasCapacity(int elements) {
2314 int length = array_->length();
2315 int required_length = length_ + elements;
2316 return (length >= required_length);
2317 }
2318
2319 void EnsureCapacity(int elements) {
2320 int length = array_->length();
2321 int required_length = length_ + elements;
2322 if (length < required_length) {
2323 int new_length = length;
2324 do {
2325 new_length *= 2;
2326 } while (new_length < required_length);
2327 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002328 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002329 array_->CopyTo(0, *extended_array, 0, length_);
2330 array_ = extended_array;
2331 }
2332 }
2333
2334 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002335 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002336 ASSERT(length_ < capacity());
2337 array_->set(length_, value);
2338 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002339 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002340 }
2341
2342 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002343 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002344 ASSERT(length_ < capacity());
2345 array_->set(length_, value);
2346 length_++;
2347 }
2348
2349 Handle<FixedArray> array() {
2350 return array_;
2351 }
2352
2353 int length() {
2354 return length_;
2355 }
2356
2357 int capacity() {
2358 return array_->length();
2359 }
2360
2361 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002362 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002363 result_array->set_length(Smi::FromInt(length_));
2364 return result_array;
2365 }
2366
2367 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002368 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002369 target_array->set_length(Smi::FromInt(length_));
2370 return target_array;
2371 }
2372
2373 private:
2374 Handle<FixedArray> array_;
2375 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002376 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002377};
2378
2379
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002380// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002381const int kStringBuilderConcatHelperLengthBits = 11;
2382const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002383
2384template <typename schar>
2385static inline void StringBuilderConcatHelper(String*,
2386 schar*,
2387 FixedArray*,
2388 int);
2389
lrn@chromium.org25156de2010-04-06 13:10:27 +00002390typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2391 StringBuilderSubstringLength;
2392typedef BitField<int,
2393 kStringBuilderConcatHelperLengthBits,
2394 kStringBuilderConcatHelperPositionBits>
2395 StringBuilderSubstringPosition;
2396
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002397
2398class ReplacementStringBuilder {
2399 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002400 ReplacementStringBuilder(Heap* heap,
2401 Handle<String> subject,
2402 int estimated_part_count)
2403 : heap_(heap),
2404 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002405 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002406 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002407 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002408 // Require a non-zero initial size. Ensures that doubling the size to
2409 // extend the array will work.
2410 ASSERT(estimated_part_count > 0);
2411 }
2412
lrn@chromium.org25156de2010-04-06 13:10:27 +00002413 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2414 int from,
2415 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002416 ASSERT(from >= 0);
2417 int length = to - from;
2418 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002419 if (StringBuilderSubstringLength::is_valid(length) &&
2420 StringBuilderSubstringPosition::is_valid(from)) {
2421 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2422 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002423 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002424 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002425 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002426 builder->Add(Smi::FromInt(-length));
2427 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002428 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002429 }
2430
2431
2432 void EnsureCapacity(int elements) {
2433 array_builder_.EnsureCapacity(elements);
2434 }
2435
2436
2437 void AddSubjectSlice(int from, int to) {
2438 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002439 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002440 }
2441
2442
2443 void AddString(Handle<String> string) {
2444 int length = string->length();
2445 ASSERT(length > 0);
2446 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002447 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002448 is_ascii_ = false;
2449 }
2450 IncrementCharacterCount(length);
2451 }
2452
2453
2454 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002455 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002456 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002457 }
2458
2459 Handle<String> joined_string;
2460 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002461 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002462 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002463 char* char_buffer = seq->GetChars();
2464 StringBuilderConcatHelper(*subject_,
2465 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002466 *array_builder_.array(),
2467 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002468 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002469 } else {
2470 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002471 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002472 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002473 uc16* char_buffer = seq->GetChars();
2474 StringBuilderConcatHelper(*subject_,
2475 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002476 *array_builder_.array(),
2477 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002478 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002479 }
2480 return joined_string;
2481 }
2482
2483
2484 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002485 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002486 V8::FatalProcessOutOfMemory("String.replace result too large.");
2487 }
2488 character_count_ += by;
2489 }
2490
lrn@chromium.org25156de2010-04-06 13:10:27 +00002491 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002492 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002493 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002494
lrn@chromium.org25156de2010-04-06 13:10:27 +00002495 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002496 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2497 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002498 }
2499
2500
ager@chromium.org04921a82011-06-27 13:21:41 +00002501 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2502 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002503 }
2504
2505
2506 void AddElement(Object* element) {
2507 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002508 ASSERT(array_builder_.capacity() > array_builder_.length());
2509 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002510 }
2511
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002512 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002513 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002514 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002515 int character_count_;
2516 bool is_ascii_;
2517};
2518
2519
2520class CompiledReplacement {
2521 public:
2522 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002523 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002524
2525 void Compile(Handle<String> replacement,
2526 int capture_count,
2527 int subject_length);
2528
2529 void Apply(ReplacementStringBuilder* builder,
2530 int match_from,
2531 int match_to,
2532 Handle<JSArray> last_match_info);
2533
2534 // Number of distinct parts of the replacement pattern.
2535 int parts() {
2536 return parts_.length();
2537 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002538
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002539 bool simple_hint() {
2540 return simple_hint_;
2541 }
2542
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002543 private:
2544 enum PartType {
2545 SUBJECT_PREFIX = 1,
2546 SUBJECT_SUFFIX,
2547 SUBJECT_CAPTURE,
2548 REPLACEMENT_SUBSTRING,
2549 REPLACEMENT_STRING,
2550
2551 NUMBER_OF_PART_TYPES
2552 };
2553
2554 struct ReplacementPart {
2555 static inline ReplacementPart SubjectMatch() {
2556 return ReplacementPart(SUBJECT_CAPTURE, 0);
2557 }
2558 static inline ReplacementPart SubjectCapture(int capture_index) {
2559 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2560 }
2561 static inline ReplacementPart SubjectPrefix() {
2562 return ReplacementPart(SUBJECT_PREFIX, 0);
2563 }
2564 static inline ReplacementPart SubjectSuffix(int subject_length) {
2565 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2566 }
2567 static inline ReplacementPart ReplacementString() {
2568 return ReplacementPart(REPLACEMENT_STRING, 0);
2569 }
2570 static inline ReplacementPart ReplacementSubString(int from, int to) {
2571 ASSERT(from >= 0);
2572 ASSERT(to > from);
2573 return ReplacementPart(-from, to);
2574 }
2575
2576 // If tag <= 0 then it is the negation of a start index of a substring of
2577 // the replacement pattern, otherwise it's a value from PartType.
2578 ReplacementPart(int tag, int data)
2579 : tag(tag), data(data) {
2580 // Must be non-positive or a PartType value.
2581 ASSERT(tag < NUMBER_OF_PART_TYPES);
2582 }
2583 // Either a value of PartType or a non-positive number that is
2584 // the negation of an index into the replacement string.
2585 int tag;
2586 // The data value's interpretation depends on the value of tag:
2587 // tag == SUBJECT_PREFIX ||
2588 // tag == SUBJECT_SUFFIX: data is unused.
2589 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2590 // tag == REPLACEMENT_SUBSTRING ||
2591 // tag == REPLACEMENT_STRING: data is index into array of substrings
2592 // of the replacement string.
2593 // tag <= 0: Temporary representation of the substring of the replacement
2594 // string ranging over -tag .. data.
2595 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2596 // substring objects.
2597 int data;
2598 };
2599
2600 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002601 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002602 Vector<Char> characters,
2603 int capture_count,
2604 int subject_length) {
2605 int length = characters.length();
2606 int last = 0;
2607 for (int i = 0; i < length; i++) {
2608 Char c = characters[i];
2609 if (c == '$') {
2610 int next_index = i + 1;
2611 if (next_index == length) { // No next character!
2612 break;
2613 }
2614 Char c2 = characters[next_index];
2615 switch (c2) {
2616 case '$':
2617 if (i > last) {
2618 // There is a substring before. Include the first "$".
2619 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2620 last = next_index + 1; // Continue after the second "$".
2621 } else {
2622 // Let the next substring start with the second "$".
2623 last = next_index;
2624 }
2625 i = next_index;
2626 break;
2627 case '`':
2628 if (i > last) {
2629 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2630 }
2631 parts->Add(ReplacementPart::SubjectPrefix());
2632 i = next_index;
2633 last = i + 1;
2634 break;
2635 case '\'':
2636 if (i > last) {
2637 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2638 }
2639 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2640 i = next_index;
2641 last = i + 1;
2642 break;
2643 case '&':
2644 if (i > last) {
2645 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2646 }
2647 parts->Add(ReplacementPart::SubjectMatch());
2648 i = next_index;
2649 last = i + 1;
2650 break;
2651 case '0':
2652 case '1':
2653 case '2':
2654 case '3':
2655 case '4':
2656 case '5':
2657 case '6':
2658 case '7':
2659 case '8':
2660 case '9': {
2661 int capture_ref = c2 - '0';
2662 if (capture_ref > capture_count) {
2663 i = next_index;
2664 continue;
2665 }
2666 int second_digit_index = next_index + 1;
2667 if (second_digit_index < length) {
2668 // Peek ahead to see if we have two digits.
2669 Char c3 = characters[second_digit_index];
2670 if ('0' <= c3 && c3 <= '9') { // Double digits.
2671 int double_digit_ref = capture_ref * 10 + c3 - '0';
2672 if (double_digit_ref <= capture_count) {
2673 next_index = second_digit_index;
2674 capture_ref = double_digit_ref;
2675 }
2676 }
2677 }
2678 if (capture_ref > 0) {
2679 if (i > last) {
2680 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2681 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002682 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002683 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2684 last = next_index + 1;
2685 }
2686 i = next_index;
2687 break;
2688 }
2689 default:
2690 i = next_index;
2691 break;
2692 }
2693 }
2694 }
2695 if (length > last) {
2696 if (last == 0) {
2697 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002698 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002699 } else {
2700 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2701 }
2702 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002703 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002704 }
2705
2706 ZoneList<ReplacementPart> parts_;
2707 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002708 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002709};
2710
2711
2712void CompiledReplacement::Compile(Handle<String> replacement,
2713 int capture_count,
2714 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002715 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002716 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002717 String::FlatContent content = replacement->GetFlatContent();
2718 ASSERT(content.IsFlat());
2719 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002720 simple_hint_ = ParseReplacementPattern(&parts_,
2721 content.ToAsciiVector(),
2722 capture_count,
2723 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002724 } else {
2725 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002726 simple_hint_ = ParseReplacementPattern(&parts_,
2727 content.ToUC16Vector(),
2728 capture_count,
2729 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002730 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002731 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002732 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002733 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002734 int substring_index = 0;
2735 for (int i = 0, n = parts_.length(); i < n; i++) {
2736 int tag = parts_[i].tag;
2737 if (tag <= 0) { // A replacement string slice.
2738 int from = -tag;
2739 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002740 replacement_substrings_.Add(
2741 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002742 parts_[i].tag = REPLACEMENT_SUBSTRING;
2743 parts_[i].data = substring_index;
2744 substring_index++;
2745 } else if (tag == REPLACEMENT_STRING) {
2746 replacement_substrings_.Add(replacement);
2747 parts_[i].data = substring_index;
2748 substring_index++;
2749 }
2750 }
2751}
2752
2753
2754void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2755 int match_from,
2756 int match_to,
2757 Handle<JSArray> last_match_info) {
2758 for (int i = 0, n = parts_.length(); i < n; i++) {
2759 ReplacementPart part = parts_[i];
2760 switch (part.tag) {
2761 case SUBJECT_PREFIX:
2762 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2763 break;
2764 case SUBJECT_SUFFIX: {
2765 int subject_length = part.data;
2766 if (match_to < subject_length) {
2767 builder->AddSubjectSlice(match_to, subject_length);
2768 }
2769 break;
2770 }
2771 case SUBJECT_CAPTURE: {
2772 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002773 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002774 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2775 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2776 if (from >= 0 && to > from) {
2777 builder->AddSubjectSlice(from, to);
2778 }
2779 break;
2780 }
2781 case REPLACEMENT_SUBSTRING:
2782 case REPLACEMENT_STRING:
2783 builder->AddString(replacement_substrings_[part.data]);
2784 break;
2785 default:
2786 UNREACHABLE();
2787 }
2788 }
2789}
2790
2791
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002792void FindAsciiStringIndices(Vector<const char> subject,
2793 char pattern,
2794 ZoneList<int>* indices,
2795 unsigned int limit) {
2796 ASSERT(limit > 0);
2797 // Collect indices of pattern in subject using memchr.
2798 // Stop after finding at most limit values.
2799 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2800 const char* subject_end = subject_start + subject.length();
2801 const char* pos = subject_start;
2802 while (limit > 0) {
2803 pos = reinterpret_cast<const char*>(
2804 memchr(pos, pattern, subject_end - pos));
2805 if (pos == NULL) return;
2806 indices->Add(static_cast<int>(pos - subject_start));
2807 pos++;
2808 limit--;
2809 }
2810}
2811
2812
2813template <typename SubjectChar, typename PatternChar>
2814void FindStringIndices(Isolate* isolate,
2815 Vector<const SubjectChar> subject,
2816 Vector<const PatternChar> pattern,
2817 ZoneList<int>* indices,
2818 unsigned int limit) {
2819 ASSERT(limit > 0);
2820 // Collect indices of pattern in subject.
2821 // Stop after finding at most limit values.
2822 int pattern_length = pattern.length();
2823 int index = 0;
2824 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2825 while (limit > 0) {
2826 index = search.Search(subject, index);
2827 if (index < 0) return;
2828 indices->Add(index);
2829 index += pattern_length;
2830 limit--;
2831 }
2832}
2833
2834
2835void FindStringIndicesDispatch(Isolate* isolate,
2836 String* subject,
2837 String* pattern,
2838 ZoneList<int>* indices,
2839 unsigned int limit) {
2840 {
2841 AssertNoAllocation no_gc;
2842 String::FlatContent subject_content = subject->GetFlatContent();
2843 String::FlatContent pattern_content = pattern->GetFlatContent();
2844 ASSERT(subject_content.IsFlat());
2845 ASSERT(pattern_content.IsFlat());
2846 if (subject_content.IsAscii()) {
2847 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2848 if (pattern_content.IsAscii()) {
2849 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2850 if (pattern_vector.length() == 1) {
2851 FindAsciiStringIndices(subject_vector,
2852 pattern_vector[0],
2853 indices,
2854 limit);
2855 } else {
2856 FindStringIndices(isolate,
2857 subject_vector,
2858 pattern_vector,
2859 indices,
2860 limit);
2861 }
2862 } else {
2863 FindStringIndices(isolate,
2864 subject_vector,
2865 pattern_content.ToUC16Vector(),
2866 indices,
2867 limit);
2868 }
2869 } else {
2870 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002871 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002872 FindStringIndices(isolate,
2873 subject_vector,
2874 pattern_content.ToAsciiVector(),
2875 indices,
2876 limit);
2877 } else {
2878 FindStringIndices(isolate,
2879 subject_vector,
2880 pattern_content.ToUC16Vector(),
2881 indices,
2882 limit);
2883 }
2884 }
2885 }
2886}
2887
2888
2889template<typename ResultSeqString>
2890MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2891 Isolate* isolate,
2892 Handle<String> subject,
2893 Handle<JSRegExp> pattern_regexp,
2894 Handle<String> replacement) {
2895 ASSERT(subject->IsFlat());
2896 ASSERT(replacement->IsFlat());
2897
2898 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2899 ZoneList<int> indices(8);
2900 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2901 String* pattern =
2902 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2903 int subject_len = subject->length();
2904 int pattern_len = pattern->length();
2905 int replacement_len = replacement->length();
2906
2907 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2908
2909 int matches = indices.length();
2910 if (matches == 0) return *subject;
2911
2912 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2913 int subject_pos = 0;
2914 int result_pos = 0;
2915
2916 Handle<ResultSeqString> result;
2917 if (ResultSeqString::kHasAsciiEncoding) {
2918 result = Handle<ResultSeqString>::cast(
2919 isolate->factory()->NewRawAsciiString(result_len));
2920 } else {
2921 result = Handle<ResultSeqString>::cast(
2922 isolate->factory()->NewRawTwoByteString(result_len));
2923 }
2924
2925 for (int i = 0; i < matches; i++) {
2926 // Copy non-matched subject content.
2927 if (subject_pos < indices.at(i)) {
2928 String::WriteToFlat(*subject,
2929 result->GetChars() + result_pos,
2930 subject_pos,
2931 indices.at(i));
2932 result_pos += indices.at(i) - subject_pos;
2933 }
2934
2935 // Replace match.
2936 if (replacement_len > 0) {
2937 String::WriteToFlat(*replacement,
2938 result->GetChars() + result_pos,
2939 0,
2940 replacement_len);
2941 result_pos += replacement_len;
2942 }
2943
2944 subject_pos = indices.at(i) + pattern_len;
2945 }
2946 // Add remaining subject content at the end.
2947 if (subject_pos < subject_len) {
2948 String::WriteToFlat(*subject,
2949 result->GetChars() + result_pos,
2950 subject_pos,
2951 subject_len);
2952 }
2953 return *result;
2954}
2955
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002956
lrn@chromium.org303ada72010-10-27 09:33:13 +00002957MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002958 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002959 String* subject,
2960 JSRegExp* regexp,
2961 String* replacement,
2962 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002963 ASSERT(subject->IsFlat());
2964 ASSERT(replacement->IsFlat());
2965
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002966 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002967
2968 int length = subject->length();
2969 Handle<String> subject_handle(subject);
2970 Handle<JSRegExp> regexp_handle(regexp);
2971 Handle<String> replacement_handle(replacement);
2972 Handle<JSArray> last_match_info_handle(last_match_info);
2973 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2974 subject_handle,
2975 0,
2976 last_match_info_handle);
2977 if (match.is_null()) {
2978 return Failure::Exception();
2979 }
2980 if (match->IsNull()) {
2981 return *subject_handle;
2982 }
2983
2984 int capture_count = regexp_handle->CaptureCount();
2985
2986 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002987 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002988 CompiledReplacement compiled_replacement;
2989 compiled_replacement.Compile(replacement_handle,
2990 capture_count,
2991 length);
2992
2993 bool is_global = regexp_handle->GetFlags().is_global();
2994
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002995 // Shortcut for simple non-regexp global replacements
2996 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002997 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002998 compiled_replacement.simple_hint()) {
2999 if (subject_handle->HasOnlyAsciiChars() &&
3000 replacement_handle->HasOnlyAsciiChars()) {
3001 return StringReplaceStringWithString<SeqAsciiString>(
3002 isolate, subject_handle, regexp_handle, replacement_handle);
3003 } else {
3004 return StringReplaceStringWithString<SeqTwoByteString>(
3005 isolate, subject_handle, regexp_handle, replacement_handle);
3006 }
3007 }
3008
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003009 // Guessing the number of parts that the final result string is built
3010 // from. Global regexps can match any number of times, so we guess
3011 // conservatively.
3012 int expected_parts =
3013 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003014 ReplacementStringBuilder builder(isolate->heap(),
3015 subject_handle,
3016 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003017
3018 // Index of end of last match.
3019 int prev = 0;
3020
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003021 // Number of parts added by compiled replacement plus preceeding
3022 // string and possibly suffix after last match. It is possible for
3023 // all components to use two elements when encoded as two smis.
3024 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003025 bool matched = true;
3026 do {
3027 ASSERT(last_match_info_handle->HasFastElements());
3028 // Increase the capacity of the builder before entering local handle-scope,
3029 // so its internal buffer can safely allocate a new handle if it grows.
3030 builder.EnsureCapacity(parts_added_per_loop);
3031
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003032 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003033 int start, end;
3034 {
3035 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003036 FixedArray* match_info_array =
3037 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003038
3039 ASSERT_EQ(capture_count * 2 + 2,
3040 RegExpImpl::GetLastCaptureCount(match_info_array));
3041 start = RegExpImpl::GetCapture(match_info_array, 0);
3042 end = RegExpImpl::GetCapture(match_info_array, 1);
3043 }
3044
3045 if (prev < start) {
3046 builder.AddSubjectSlice(prev, start);
3047 }
3048 compiled_replacement.Apply(&builder,
3049 start,
3050 end,
3051 last_match_info_handle);
3052 prev = end;
3053
3054 // Only continue checking for global regexps.
3055 if (!is_global) break;
3056
3057 // Continue from where the match ended, unless it was an empty match.
3058 int next = end;
3059 if (start == end) {
3060 next = end + 1;
3061 if (next > length) break;
3062 }
3063
3064 match = RegExpImpl::Exec(regexp_handle,
3065 subject_handle,
3066 next,
3067 last_match_info_handle);
3068 if (match.is_null()) {
3069 return Failure::Exception();
3070 }
3071 matched = !match->IsNull();
3072 } while (matched);
3073
3074 if (prev < length) {
3075 builder.AddSubjectSlice(prev, length);
3076 }
3077
3078 return *(builder.ToString());
3079}
3080
3081
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003082template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003083MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003084 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003085 String* subject,
3086 JSRegExp* regexp,
3087 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003088 ASSERT(subject->IsFlat());
3089
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003090 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003091
3092 Handle<String> subject_handle(subject);
3093 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003094
3095 // Shortcut for simple non-regexp global replacements
3096 if (regexp_handle->GetFlags().is_global() &&
3097 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3098 Handle<String> empty_string_handle(HEAP->empty_string());
3099 if (subject_handle->HasOnlyAsciiChars()) {
3100 return StringReplaceStringWithString<SeqAsciiString>(
3101 isolate, subject_handle, regexp_handle, empty_string_handle);
3102 } else {
3103 return StringReplaceStringWithString<SeqTwoByteString>(
3104 isolate, subject_handle, regexp_handle, empty_string_handle);
3105 }
3106 }
3107
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003108 Handle<JSArray> last_match_info_handle(last_match_info);
3109 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3110 subject_handle,
3111 0,
3112 last_match_info_handle);
3113 if (match.is_null()) return Failure::Exception();
3114 if (match->IsNull()) return *subject_handle;
3115
3116 ASSERT(last_match_info_handle->HasFastElements());
3117
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003118 int start, end;
3119 {
3120 AssertNoAllocation match_info_array_is_not_in_a_handle;
3121 FixedArray* match_info_array =
3122 FixedArray::cast(last_match_info_handle->elements());
3123
3124 start = RegExpImpl::GetCapture(match_info_array, 0);
3125 end = RegExpImpl::GetCapture(match_info_array, 1);
3126 }
3127
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003128 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003129 int new_length = length - (end - start);
3130 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003131 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003132 }
3133 Handle<ResultSeqString> answer;
3134 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003135 answer = Handle<ResultSeqString>::cast(
3136 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003137 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003138 answer = Handle<ResultSeqString>::cast(
3139 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003140 }
3141
3142 // If the regexp isn't global, only match once.
3143 if (!regexp_handle->GetFlags().is_global()) {
3144 if (start > 0) {
3145 String::WriteToFlat(*subject_handle,
3146 answer->GetChars(),
3147 0,
3148 start);
3149 }
3150 if (end < length) {
3151 String::WriteToFlat(*subject_handle,
3152 answer->GetChars() + start,
3153 end,
3154 length);
3155 }
3156 return *answer;
3157 }
3158
3159 int prev = 0; // Index of end of last match.
3160 int next = 0; // Start of next search (prev unless last match was empty).
3161 int position = 0;
3162
3163 do {
3164 if (prev < start) {
3165 // Add substring subject[prev;start] to answer string.
3166 String::WriteToFlat(*subject_handle,
3167 answer->GetChars() + position,
3168 prev,
3169 start);
3170 position += start - prev;
3171 }
3172 prev = end;
3173 next = end;
3174 // Continue from where the match ended, unless it was an empty match.
3175 if (start == end) {
3176 next++;
3177 if (next > length) break;
3178 }
3179 match = RegExpImpl::Exec(regexp_handle,
3180 subject_handle,
3181 next,
3182 last_match_info_handle);
3183 if (match.is_null()) return Failure::Exception();
3184 if (match->IsNull()) break;
3185
3186 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003187 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003188 {
3189 AssertNoAllocation match_info_array_is_not_in_a_handle;
3190 FixedArray* match_info_array =
3191 FixedArray::cast(last_match_info_handle->elements());
3192 start = RegExpImpl::GetCapture(match_info_array, 0);
3193 end = RegExpImpl::GetCapture(match_info_array, 1);
3194 }
3195 } while (true);
3196
3197 if (prev < length) {
3198 // Add substring subject[prev;length] to answer string.
3199 String::WriteToFlat(*subject_handle,
3200 answer->GetChars() + position,
3201 prev,
3202 length);
3203 position += length - prev;
3204 }
3205
3206 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003207 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003208 }
3209
3210 // Shorten string and fill
3211 int string_size = ResultSeqString::SizeFor(position);
3212 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3213 int delta = allocated_string_size - string_size;
3214
3215 answer->set_length(position);
3216 if (delta == 0) return *answer;
3217
3218 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003219 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003220 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003221 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003222 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003223
3224 return *answer;
3225}
3226
3227
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003228RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003229 ASSERT(args.length() == 4);
3230
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003231 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003232 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003233 Object* flat_subject;
3234 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3235 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3236 return maybe_flat_subject;
3237 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003238 }
3239 subject = String::cast(flat_subject);
3240 }
3241
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003242 CONVERT_ARG_CHECKED(String, replacement, 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003243 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003244 Object* flat_replacement;
3245 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3246 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3247 return maybe_flat_replacement;
3248 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003249 }
3250 replacement = String::cast(flat_replacement);
3251 }
3252
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003253 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3254 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003255
3256 ASSERT(last_match_info->HasFastElements());
3257
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003258 if (replacement->length() == 0) {
3259 if (subject->HasOnlyAsciiChars()) {
3260 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003261 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003262 } else {
3263 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003264 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003265 }
3266 }
3267
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003268 return StringReplaceRegExpWithString(isolate,
3269 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003270 regexp,
3271 replacement,
3272 last_match_info);
3273}
3274
3275
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003276Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3277 Handle<String> subject,
3278 Handle<String> search,
3279 Handle<String> replace,
3280 bool* found,
3281 int recursion_limit) {
3282 if (recursion_limit == 0) return Handle<String>::null();
3283 if (subject->IsConsString()) {
3284 ConsString* cons = ConsString::cast(*subject);
3285 Handle<String> first = Handle<String>(cons->first());
3286 Handle<String> second = Handle<String>(cons->second());
3287 Handle<String> new_first =
3288 StringReplaceOneCharWithString(isolate,
3289 first,
3290 search,
3291 replace,
3292 found,
3293 recursion_limit - 1);
3294 if (*found) return isolate->factory()->NewConsString(new_first, second);
3295 if (new_first.is_null()) return new_first;
3296
3297 Handle<String> new_second =
3298 StringReplaceOneCharWithString(isolate,
3299 second,
3300 search,
3301 replace,
3302 found,
3303 recursion_limit - 1);
3304 if (*found) return isolate->factory()->NewConsString(first, new_second);
3305 if (new_second.is_null()) return new_second;
3306
3307 return subject;
3308 } else {
3309 int index = StringMatch(isolate, subject, search, 0);
3310 if (index == -1) return subject;
3311 *found = true;
3312 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3313 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3314 Handle<String> second =
3315 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3316 return isolate->factory()->NewConsString(cons1, second);
3317 }
3318}
3319
3320
3321RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3322 ASSERT(args.length() == 3);
3323 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003324 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3325 CONVERT_ARG_HANDLE_CHECKED(String, search, 1);
3326 CONVERT_ARG_HANDLE_CHECKED(String, replace, 2);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003327
3328 // If the cons string tree is too deep, we simply abort the recursion and
3329 // retry with a flattened subject string.
3330 const int kRecursionLimit = 0x1000;
3331 bool found = false;
3332 Handle<String> result =
3333 Runtime::StringReplaceOneCharWithString(isolate,
3334 subject,
3335 search,
3336 replace,
3337 &found,
3338 kRecursionLimit);
3339 if (!result.is_null()) return *result;
3340 return *Runtime::StringReplaceOneCharWithString(isolate,
3341 FlattenGetString(subject),
3342 search,
3343 replace,
3344 &found,
3345 kRecursionLimit);
3346}
3347
3348
ager@chromium.org7c537e22008-10-16 08:43:32 +00003349// Perform string match of pattern on subject, starting at start index.
3350// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003351// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003352int Runtime::StringMatch(Isolate* isolate,
3353 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003354 Handle<String> pat,
3355 int start_index) {
3356 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003357 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003358
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003359 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003360 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003361
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003362 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003363 if (start_index + pattern_length > subject_length) return -1;
3364
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003365 if (!sub->IsFlat()) FlattenString(sub);
3366 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003367
ager@chromium.org7c537e22008-10-16 08:43:32 +00003368 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003369 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003370 String::FlatContent seq_sub = sub->GetFlatContent();
3371 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003372
ager@chromium.org7c537e22008-10-16 08:43:32 +00003373 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003374 if (seq_pat.IsAscii()) {
3375 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3376 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003377 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003378 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003379 pat_vector,
3380 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003381 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003382 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003383 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003384 pat_vector,
3385 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003386 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003387 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3388 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003389 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003390 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003391 pat_vector,
3392 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003393 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003394 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003395 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003396 pat_vector,
3397 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003398}
3399
3400
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003401RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003402 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003403 ASSERT(args.length() == 3);
3404
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003405 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3406 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003407
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003408 Object* index = args[2];
3409 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003410 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003411
ager@chromium.org870a0b62008-11-04 11:43:05 +00003412 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003413 int position =
3414 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003415 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003416}
3417
3418
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003419template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003420static int StringMatchBackwards(Vector<const schar> subject,
3421 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003422 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003423 int pattern_length = pattern.length();
3424 ASSERT(pattern_length >= 1);
3425 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003426
3427 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003428 for (int i = 0; i < pattern_length; i++) {
3429 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003430 if (c > String::kMaxAsciiCharCode) {
3431 return -1;
3432 }
3433 }
3434 }
3435
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003436 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003437 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003438 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003439 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003440 while (j < pattern_length) {
3441 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003442 break;
3443 }
3444 j++;
3445 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003446 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003447 return i;
3448 }
3449 }
3450 return -1;
3451}
3452
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003453RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003454 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003455 ASSERT(args.length() == 3);
3456
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003457 CONVERT_ARG_HANDLE_CHECKED(String, sub, 0);
3458 CONVERT_ARG_HANDLE_CHECKED(String, pat, 1);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003459
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003460 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003461 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003462 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003463
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003464 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003465 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003466
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003467 if (start_index + pat_length > sub_length) {
3468 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003469 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003470
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003471 if (pat_length == 0) {
3472 return Smi::FromInt(start_index);
3473 }
3474
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003475 if (!sub->IsFlat()) FlattenString(sub);
3476 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003477
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003478 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003479 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3480
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003481 String::FlatContent sub_content = sub->GetFlatContent();
3482 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003483
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003484 if (pat_content.IsAscii()) {
3485 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3486 if (sub_content.IsAscii()) {
3487 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003488 pat_vector,
3489 start_index);
3490 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003491 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003492 pat_vector,
3493 start_index);
3494 }
3495 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003496 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3497 if (sub_content.IsAscii()) {
3498 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003499 pat_vector,
3500 start_index);
3501 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003502 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003503 pat_vector,
3504 start_index);
3505 }
3506 }
3507
3508 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003509}
3510
3511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003512RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003513 NoHandleAllocation ha;
3514 ASSERT(args.length() == 2);
3515
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003516 CONVERT_ARG_CHECKED(String, str1, 0);
3517 CONVERT_ARG_CHECKED(String, str2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003518
3519 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003520 int str1_length = str1->length();
3521 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003522
3523 // Decide trivial cases without flattening.
3524 if (str1_length == 0) {
3525 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3526 return Smi::FromInt(-str2_length);
3527 } else {
3528 if (str2_length == 0) return Smi::FromInt(str1_length);
3529 }
3530
3531 int end = str1_length < str2_length ? str1_length : str2_length;
3532
3533 // No need to flatten if we are going to find the answer on the first
3534 // character. At this point we know there is at least one character
3535 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003536 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003537 if (d != 0) return Smi::FromInt(d);
3538
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003539 str1->TryFlatten();
3540 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003541
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003542 StringInputBuffer& buf1 =
3543 *isolate->runtime_state()->string_locale_compare_buf1();
3544 StringInputBuffer& buf2 =
3545 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003546
3547 buf1.Reset(str1);
3548 buf2.Reset(str2);
3549
3550 for (int i = 0; i < end; i++) {
3551 uint16_t char1 = buf1.GetNext();
3552 uint16_t char2 = buf2.GetNext();
3553 if (char1 != char2) return Smi::FromInt(char1 - char2);
3554 }
3555
3556 return Smi::FromInt(str1_length - str2_length);
3557}
3558
3559
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003560RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003561 NoHandleAllocation ha;
3562 ASSERT(args.length() == 3);
3563
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003564 CONVERT_ARG_CHECKED(String, value, 0);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003565 int start, end;
3566 // We have a fast integer-only case here to avoid a conversion to double in
3567 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003568 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3569 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3570 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3571 start = from_number;
3572 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003573 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003574 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3575 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003576 start = FastD2I(from_number);
3577 end = FastD2I(to_number);
3578 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003579 RUNTIME_ASSERT(end >= start);
3580 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003581 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003582 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003583 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003584}
3585
3586
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003587RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003588 ASSERT_EQ(3, args.length());
3589
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003590 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
3591 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 1);
3592 CONVERT_ARG_HANDLE_CHECKED(JSArray, regexp_info, 2);
ager@chromium.org41826e72009-03-30 13:30:57 +00003593 HandleScope handles;
3594
3595 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3596
3597 if (match.is_null()) {
3598 return Failure::Exception();
3599 }
3600 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003601 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003602 }
3603 int length = subject->length();
3604
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003605 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003606 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003607 int start;
3608 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003609 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003610 {
3611 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003612 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003613 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3614 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3615 }
3616 offsets.Add(start);
3617 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003618 if (start == end) if (++end > length) break;
3619 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003620 if (match.is_null()) {
3621 return Failure::Exception();
3622 }
3623 } while (!match->IsNull());
3624 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003625 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003626 Handle<String> substring = isolate->factory()->
3627 NewSubString(subject, offsets.at(0), offsets.at(1));
3628 elements->set(0, *substring);
3629 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003630 int from = offsets.at(i * 2);
3631 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003632 Handle<String> substring = isolate->factory()->
3633 NewProperSubString(subject, from, to);
3634 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003635 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003636 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003637 result->set_length(Smi::FromInt(matches));
3638 return *result;
3639}
3640
3641
lrn@chromium.org25156de2010-04-06 13:10:27 +00003642// Two smis before and after the match, for very long strings.
3643const int kMaxBuilderEntriesPerRegExpMatch = 5;
3644
3645
3646static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3647 Handle<JSArray> last_match_info,
3648 int match_start,
3649 int match_end) {
3650 // Fill last_match_info with a single capture.
3651 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3652 AssertNoAllocation no_gc;
3653 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3654 RegExpImpl::SetLastCaptureCount(elements, 2);
3655 RegExpImpl::SetLastInput(elements, *subject);
3656 RegExpImpl::SetLastSubject(elements, *subject);
3657 RegExpImpl::SetCapture(elements, 0, match_start);
3658 RegExpImpl::SetCapture(elements, 1, match_end);
3659}
3660
3661
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003662template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003663static bool SearchStringMultiple(Isolate* isolate,
3664 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003665 Vector<const PatternChar> pattern,
3666 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003667 FixedArrayBuilder* builder,
3668 int* match_pos) {
3669 int pos = *match_pos;
3670 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003671 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003672 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003673 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003674 while (pos <= max_search_start) {
3675 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3676 *match_pos = pos;
3677 return false;
3678 }
3679 // Position of end of previous match.
3680 int match_end = pos + pattern_length;
3681 int new_pos = search.Search(subject, match_end);
3682 if (new_pos >= 0) {
3683 // A match.
3684 if (new_pos > match_end) {
3685 ReplacementStringBuilder::AddSubjectSlice(builder,
3686 match_end,
3687 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003688 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003689 pos = new_pos;
3690 builder->Add(pattern_string);
3691 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003692 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003693 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003694 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003695
lrn@chromium.org25156de2010-04-06 13:10:27 +00003696 if (pos < max_search_start) {
3697 ReplacementStringBuilder::AddSubjectSlice(builder,
3698 pos + pattern_length,
3699 subject_length);
3700 }
3701 *match_pos = pos;
3702 return true;
3703}
3704
3705
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003706static bool SearchStringMultiple(Isolate* isolate,
3707 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003708 Handle<String> pattern,
3709 Handle<JSArray> last_match_info,
3710 FixedArrayBuilder* builder) {
3711 ASSERT(subject->IsFlat());
3712 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003713
3714 // Treating as if a previous match was before first character.
3715 int match_pos = -pattern->length();
3716
3717 for (;;) { // Break when search complete.
3718 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3719 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003720 String::FlatContent subject_content = subject->GetFlatContent();
3721 String::FlatContent pattern_content = pattern->GetFlatContent();
3722 if (subject_content.IsAscii()) {
3723 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3724 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003725 if (SearchStringMultiple(isolate,
3726 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003727 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003728 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003729 builder,
3730 &match_pos)) break;
3731 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003732 if (SearchStringMultiple(isolate,
3733 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003734 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003735 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003736 builder,
3737 &match_pos)) break;
3738 }
3739 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003740 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3741 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003742 if (SearchStringMultiple(isolate,
3743 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003744 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003745 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003746 builder,
3747 &match_pos)) break;
3748 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003749 if (SearchStringMultiple(isolate,
3750 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003751 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003752 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003753 builder,
3754 &match_pos)) break;
3755 }
3756 }
3757 }
3758
3759 if (match_pos >= 0) {
3760 SetLastMatchInfoNoCaptures(subject,
3761 last_match_info,
3762 match_pos,
3763 match_pos + pattern->length());
3764 return true;
3765 }
3766 return false; // No matches at all.
3767}
3768
3769
3770static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003771 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003772 Handle<String> subject,
3773 Handle<JSRegExp> regexp,
3774 Handle<JSArray> last_match_array,
3775 FixedArrayBuilder* builder) {
3776 ASSERT(subject->IsFlat());
3777 int match_start = -1;
3778 int match_end = 0;
3779 int pos = 0;
3780 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3781 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3782
ulan@chromium.org812308e2012-02-29 15:58:45 +00003783 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003784 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003785 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003786 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003787
3788 for (;;) { // Break on failure, return on exception.
3789 RegExpImpl::IrregexpResult result =
3790 RegExpImpl::IrregexpExecOnce(regexp,
3791 subject,
3792 pos,
3793 register_vector);
3794 if (result == RegExpImpl::RE_SUCCESS) {
3795 match_start = register_vector[0];
3796 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3797 if (match_end < match_start) {
3798 ReplacementStringBuilder::AddSubjectSlice(builder,
3799 match_end,
3800 match_start);
3801 }
3802 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003803 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003804 if (!first) {
3805 builder->Add(*isolate->factory()->NewProperSubString(subject,
3806 match_start,
3807 match_end));
3808 } else {
3809 builder->Add(*isolate->factory()->NewSubString(subject,
3810 match_start,
3811 match_end));
3812 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003813 if (match_start != match_end) {
3814 pos = match_end;
3815 } else {
3816 pos = match_end + 1;
3817 if (pos > subject_length) break;
3818 }
3819 } else if (result == RegExpImpl::RE_FAILURE) {
3820 break;
3821 } else {
3822 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3823 return result;
3824 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003825 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003826 }
3827
3828 if (match_start >= 0) {
3829 if (match_end < subject_length) {
3830 ReplacementStringBuilder::AddSubjectSlice(builder,
3831 match_end,
3832 subject_length);
3833 }
3834 SetLastMatchInfoNoCaptures(subject,
3835 last_match_array,
3836 match_start,
3837 match_end);
3838 return RegExpImpl::RE_SUCCESS;
3839 } else {
3840 return RegExpImpl::RE_FAILURE; // No matches at all.
3841 }
3842}
3843
3844
3845static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003846 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003847 Handle<String> subject,
3848 Handle<JSRegExp> regexp,
3849 Handle<JSArray> last_match_array,
3850 FixedArrayBuilder* builder) {
3851
3852 ASSERT(subject->IsFlat());
3853 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3854 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3855
ulan@chromium.org812308e2012-02-29 15:58:45 +00003856 OffsetsVector registers(required_registers, isolate);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003857 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003858
3859 RegExpImpl::IrregexpResult result =
3860 RegExpImpl::IrregexpExecOnce(regexp,
3861 subject,
3862 0,
3863 register_vector);
3864
3865 int capture_count = regexp->CaptureCount();
3866 int subject_length = subject->length();
3867
3868 // Position to search from.
3869 int pos = 0;
3870 // End of previous match. Differs from pos if match was empty.
3871 int match_end = 0;
3872 if (result == RegExpImpl::RE_SUCCESS) {
3873 // Need to keep a copy of the previous match for creating last_match_info
3874 // at the end, so we have two vectors that we swap between.
ulan@chromium.org812308e2012-02-29 15:58:45 +00003875 OffsetsVector registers2(required_registers, isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003876 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003877 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003878 do {
3879 int match_start = register_vector[0];
3880 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3881 if (match_end < match_start) {
3882 ReplacementStringBuilder::AddSubjectSlice(builder,
3883 match_end,
3884 match_start);
3885 }
3886 match_end = register_vector[1];
3887
3888 {
3889 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003890 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003891 // Arguments array to replace function is match, captures, index and
3892 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003893 Handle<FixedArray> elements =
3894 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003895 Handle<String> match;
3896 if (!first) {
3897 match = isolate->factory()->NewProperSubString(subject,
3898 match_start,
3899 match_end);
3900 } else {
3901 match = isolate->factory()->NewSubString(subject,
3902 match_start,
3903 match_end);
3904 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003905 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003906 for (int i = 1; i <= capture_count; i++) {
3907 int start = register_vector[i * 2];
3908 if (start >= 0) {
3909 int end = register_vector[i * 2 + 1];
3910 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003911 Handle<String> substring;
3912 if (!first) {
3913 substring = isolate->factory()->NewProperSubString(subject,
3914 start,
3915 end);
3916 } else {
3917 substring = isolate->factory()->NewSubString(subject, start, end);
3918 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003919 elements->set(i, *substring);
3920 } else {
3921 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003922 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003923 }
3924 }
3925 elements->set(capture_count + 1, Smi::FromInt(match_start));
3926 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003927 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003928 }
3929 // Swap register vectors, so the last successful match is in
3930 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003931 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003932 prev_register_vector = register_vector;
3933 register_vector = tmp;
3934
3935 if (match_end > match_start) {
3936 pos = match_end;
3937 } else {
3938 pos = match_end + 1;
3939 if (pos > subject_length) {
3940 break;
3941 }
3942 }
3943
3944 result = RegExpImpl::IrregexpExecOnce(regexp,
3945 subject,
3946 pos,
3947 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003948 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003949 } while (result == RegExpImpl::RE_SUCCESS);
3950
3951 if (result != RegExpImpl::RE_EXCEPTION) {
3952 // Finished matching, with at least one match.
3953 if (match_end < subject_length) {
3954 ReplacementStringBuilder::AddSubjectSlice(builder,
3955 match_end,
3956 subject_length);
3957 }
3958
3959 int last_match_capture_count = (capture_count + 1) * 2;
3960 int last_match_array_size =
3961 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3962 last_match_array->EnsureSize(last_match_array_size);
3963 AssertNoAllocation no_gc;
3964 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3965 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3966 RegExpImpl::SetLastSubject(elements, *subject);
3967 RegExpImpl::SetLastInput(elements, *subject);
3968 for (int i = 0; i < last_match_capture_count; i++) {
3969 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3970 }
3971 return RegExpImpl::RE_SUCCESS;
3972 }
3973 }
3974 // No matches at all, return failure or exception result directly.
3975 return result;
3976}
3977
3978
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003979RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003980 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003981 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003982
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003983 CONVERT_ARG_HANDLE_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003984 if (!subject->IsFlat()) FlattenString(subject);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00003985 CONVERT_ARG_HANDLE_CHECKED(JSRegExp, regexp, 0);
3986 CONVERT_ARG_HANDLE_CHECKED(JSArray, last_match_info, 2);
3987 CONVERT_ARG_HANDLE_CHECKED(JSArray, result_array, 3);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003988
3989 ASSERT(last_match_info->HasFastElements());
3990 ASSERT(regexp->GetFlags().is_global());
3991 Handle<FixedArray> result_elements;
3992 if (result_array->HasFastElements()) {
3993 result_elements =
3994 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003995 }
3996 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003997 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003998 }
3999 FixedArrayBuilder builder(result_elements);
4000
4001 if (regexp->TypeTag() == JSRegExp::ATOM) {
4002 Handle<String> pattern(
4003 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004004 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004005 if (SearchStringMultiple(isolate, subject, pattern,
4006 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00004007 return *builder.ToJSArray(result_array);
4008 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004009 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004010 }
4011
4012 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
4013
4014 RegExpImpl::IrregexpResult result;
4015 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004016 result = SearchRegExpNoCaptureMultiple(isolate,
4017 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00004018 regexp,
4019 last_match_info,
4020 &builder);
4021 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004022 result = SearchRegExpMultiple(isolate,
4023 subject,
4024 regexp,
4025 last_match_info,
4026 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004027 }
4028 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004029 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004030 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
4031 return Failure::Exception();
4032}
4033
4034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004035RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004036 NoHandleAllocation ha;
4037 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004038 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004039 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004040
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004041 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004042 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004043 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004044 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004045 // Character array used for conversion.
4046 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004047 return isolate->heap()->
4048 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004049 }
4050 }
4051
4052 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004053 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004055 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004056 }
4057 if (isinf(value)) {
4058 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004059 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004060 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004061 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004062 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004063 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004064 MaybeObject* result =
4065 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004066 DeleteArray(str);
4067 return result;
4068}
4069
4070
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004071RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004072 NoHandleAllocation ha;
4073 ASSERT(args.length() == 2);
4074
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004075 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004076 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004077 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004078 }
4079 if (isinf(value)) {
4080 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004081 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004082 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004083 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004084 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004085 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004086 int f = FastD2I(f_number);
4087 RUNTIME_ASSERT(f >= 0);
4088 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004089 MaybeObject* res =
4090 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004091 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004092 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004093}
4094
4095
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004096RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004097 NoHandleAllocation ha;
4098 ASSERT(args.length() == 2);
4099
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004100 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004101 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004102 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004103 }
4104 if (isinf(value)) {
4105 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004106 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004107 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004108 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004109 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004110 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004111 int f = FastD2I(f_number);
4112 RUNTIME_ASSERT(f >= -1 && f <= 20);
4113 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004114 MaybeObject* res =
4115 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004116 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004117 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004118}
4119
4120
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004121RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004122 NoHandleAllocation ha;
4123 ASSERT(args.length() == 2);
4124
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004125 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004126 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004127 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004128 }
4129 if (isinf(value)) {
4130 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004131 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004132 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004133 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004134 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004135 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004136 int f = FastD2I(f_number);
4137 RUNTIME_ASSERT(f >= 1 && f <= 21);
4138 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004139 MaybeObject* res =
4140 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004141 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004142 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004143}
4144
4145
4146// Returns a single character string where first character equals
4147// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004148static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004149 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004150 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004151 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004152 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004153 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004154 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004155}
4156
4157
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004158MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4159 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004160 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004161 // Handle [] indexing on Strings
4162 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004163 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4164 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004165 }
4166
4167 // Handle [] indexing on String objects
4168 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004169 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4170 Handle<Object> result =
4171 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4172 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004173 }
4174
4175 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004176 return object->GetPrototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004177 }
4178
4179 return object->GetElement(index);
4180}
4181
4182
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004183MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4184 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004185 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004186 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004187
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004188 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004189 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004191 isolate->factory()->NewTypeError("non_object_property_load",
4192 HandleVector(args, 2));
4193 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004194 }
4195
4196 // Check if the given key is an array index.
4197 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004198 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004199 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004200 }
4201
4202 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004203 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004204 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004205 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004206 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004207 bool has_pending_exception = false;
4208 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004209 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004210 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004211 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004212 }
4213
ager@chromium.org32912102009-01-16 10:38:43 +00004214 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004215 // the element if so.
4216 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004217 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004218 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004219 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004220 }
4221}
4222
4223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004224RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004225 NoHandleAllocation ha;
4226 ASSERT(args.length() == 2);
4227
4228 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004229 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004230
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004231 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004232}
4233
4234
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004235// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004236RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004237 NoHandleAllocation ha;
4238 ASSERT(args.length() == 2);
4239
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004240 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004241 // itself.
4242 //
4243 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004244 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004245 // global proxy object never has properties. This is the case
4246 // because the global proxy object forwards everything to its hidden
4247 // prototype including local lookups.
4248 //
4249 // Additionally, we need to make sure that we do not cache results
4250 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004251 if (args[0]->IsJSObject()) {
4252 if (!args[0]->IsJSGlobalProxy() &&
4253 !args[0]->IsAccessCheckNeeded() &&
4254 args[1]->IsString()) {
4255 JSObject* receiver = JSObject::cast(args[0]);
4256 String* key = String::cast(args[1]);
4257 if (receiver->HasFastProperties()) {
4258 // Attempt to use lookup cache.
4259 Map* receiver_map = receiver->map();
4260 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4261 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4262 if (offset != -1) {
4263 Object* value = receiver->FastPropertyAt(offset);
4264 return value->IsTheHole()
4265 ? isolate->heap()->undefined_value()
4266 : value;
4267 }
4268 // Lookup cache miss. Perform lookup and update the cache if
4269 // appropriate.
4270 LookupResult result(isolate);
4271 receiver->LocalLookup(key, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004272 if (result.IsFound() && result.type() == FIELD) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004273 int offset = result.GetFieldIndex();
4274 keyed_lookup_cache->Update(receiver_map, key, offset);
4275 return receiver->FastPropertyAt(offset);
4276 }
4277 } else {
4278 // Attempt dictionary lookup.
4279 StringDictionary* dictionary = receiver->property_dictionary();
4280 int entry = dictionary->FindEntry(key);
4281 if ((entry != StringDictionary::kNotFound) &&
4282 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4283 Object* value = dictionary->ValueAt(entry);
4284 if (!receiver->IsGlobalObject()) return value;
4285 value = JSGlobalPropertyCell::cast(value)->value();
4286 if (!value->IsTheHole()) return value;
4287 // If value is the hole do the general lookup.
4288 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004289 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004290 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4291 // JSObject without a string key. If the key is a Smi, check for a
4292 // definite out-of-bounds access to elements, which is a strong indicator
4293 // that subsequent accesses will also call the runtime. Proactively
4294 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4295 // doubles for those future calls in the case that the elements would
4296 // become FAST_DOUBLE_ELEMENTS.
4297 Handle<JSObject> js_object(args.at<JSObject>(0));
4298 ElementsKind elements_kind = js_object->GetElementsKind();
4299 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4300 elements_kind == FAST_DOUBLE_ELEMENTS) {
4301 FixedArrayBase* elements = js_object->elements();
4302 if (args.at<Smi>(1)->value() >= elements->length()) {
4303 MaybeObject* maybe_object = TransitionElements(js_object,
4304 FAST_ELEMENTS,
4305 isolate);
4306 if (maybe_object->IsFailure()) return maybe_object;
4307 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004308 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004309 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004310 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4311 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004312 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004313 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004314 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004315 if (index >= 0 && index < str->length()) {
4316 Handle<Object> result = GetCharAt(str, index);
4317 return *result;
4318 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004319 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004320
4321 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004322 return Runtime::GetObjectProperty(isolate,
4323 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004324 args.at<Object>(1));
4325}
4326
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004327
4328static bool IsValidAccessor(Handle<Object> obj) {
4329 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
4330}
4331
4332
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004333// Implements part of 8.12.9 DefineOwnProperty.
4334// There are 3 cases that lead here:
4335// Step 4b - define a new accessor property.
4336// Steps 9c & 12 - replace an existing data property with an accessor property.
4337// Step 12 - update an existing accessor property with an accessor or generic
4338// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004339RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004340 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004341 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004342 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004343 RUNTIME_ASSERT(!obj->IsNull());
4344 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
4345 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
4346 RUNTIME_ASSERT(IsValidAccessor(getter));
4347 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
4348 RUNTIME_ASSERT(IsValidAccessor(setter));
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004349 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
ager@chromium.org5c838252010-02-19 08:53:10 +00004350 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004351 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004352
danno@chromium.org88aa0582012-03-23 15:11:57 +00004353 bool fast = obj->HasFastProperties();
4354 JSObject::DefineAccessor(obj, name, getter, setter, attr);
4355 if (fast) JSObject::TransformToFastProperties(obj, 0);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004356 return isolate->heap()->undefined_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00004357}
4358
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004359// Implements part of 8.12.9 DefineOwnProperty.
4360// There are 3 cases that lead here:
4361// Step 4a - define a new data property.
4362// Steps 9b & 12 - replace an existing accessor property with a data property.
4363// Step 12 - update an existing data property with a data or generic
4364// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004365RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004366 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004367 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004368 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
4369 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00004370 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004371 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
ager@chromium.org5c838252010-02-19 08:53:10 +00004372 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004373 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4374
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004375 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004376 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004377
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004378 // Special case for callback properties.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004379 if (result.IsFound() && result.type() == CALLBACKS) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004380 Object* callback = result.GetCallbackObject();
4381 // To be compatible with Safari we do not change the value on API objects
4382 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4383 // the value.
4384 if (callback->IsAccessorInfo()) {
4385 return isolate->heap()->undefined_value();
4386 }
4387 // Avoid redefining foreign callback as data property, just use the stored
4388 // setter to update the value instead.
4389 // TODO(mstarzinger): So far this only works if property attributes don't
4390 // change, this should be fixed once we cleanup the underlying code.
4391 if (callback->IsForeign() && result.GetAttributes() == attr) {
4392 return js_object->SetPropertyWithCallback(callback,
4393 *name,
4394 *obj_value,
4395 result.holder(),
4396 kStrictMode);
4397 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004398 }
4399
ager@chromium.org5c838252010-02-19 08:53:10 +00004400 // Take special care when attributes are different and there is already
4401 // a property. For simplicity we normalize the property which enables us
4402 // to not worry about changing the instance_descriptor and creating a new
4403 // map. The current version of SetObjectProperty does not handle attributes
4404 // correctly in the case where a property is a field and is reset with
4405 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004406 if (result.IsProperty() &&
4407 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004408 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004409 if (js_object->IsJSGlobalProxy()) {
4410 // Since the result is a property, the prototype will exist so
4411 // we don't have to check for null.
4412 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004413 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004414 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004415 // Use IgnoreAttributes version since a readonly property may be
4416 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004417 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4418 *obj_value,
4419 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004420 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004421
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004422 return Runtime::ForceSetObjectProperty(isolate,
4423 js_object,
4424 name,
4425 obj_value,
4426 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004427}
4428
4429
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004430MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4431 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004432 Handle<Object> key,
4433 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004434 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004435 StrictModeFlag strict_mode) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004436 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004437 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004438
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004439 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004440 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004441 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004442 isolate->factory()->NewTypeError("non_object_property_store",
4443 HandleVector(args, 2));
4444 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004445 }
4446
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004447 if (object->IsJSProxy()) {
4448 bool has_pending_exception = false;
4449 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4450 if (has_pending_exception) return Failure::Exception();
4451 return JSProxy::cast(*object)->SetProperty(
4452 String::cast(*name), *value, attr, strict_mode);
4453 }
4454
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004455 // If the object isn't a JavaScript object, we ignore the store.
4456 if (!object->IsJSObject()) return *value;
4457
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004458 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4459
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004460 // Check if the given key is an array index.
4461 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004462 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004463 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4464 // of a string using [] notation. We need to support this too in
4465 // JavaScript.
4466 // In the case of a String object we just need to redirect the assignment to
4467 // the underlying string if the index is in range. Since the underlying
4468 // string does nothing with the assignment then we can ignore such
4469 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004470 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004471 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004472 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004473
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004474 Handle<Object> result = JSObject::SetElement(
4475 js_object, index, value, attr, strict_mode, set_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004476 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004477 return *value;
4478 }
4479
4480 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004481 Handle<Object> result;
4482 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004483 result = JSObject::SetElement(
4484 js_object, index, value, attr, strict_mode, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004485 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004486 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004487 key_string->TryFlatten();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004488 result = JSReceiver::SetProperty(
4489 js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004490 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004491 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004492 return *value;
4493 }
4494
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004495 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004496 bool has_pending_exception = false;
4497 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4498 if (has_pending_exception) return Failure::Exception();
4499 Handle<String> name = Handle<String>::cast(converted);
4500
4501 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004502 return js_object->SetElement(
4503 index, *value, attr, strict_mode, true, set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004504 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004505 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004506 }
4507}
4508
4509
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004510MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4511 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004512 Handle<Object> key,
4513 Handle<Object> value,
4514 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004515 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004516
4517 // Check if the given key is an array index.
4518 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004519 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004520 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4521 // of a string using [] notation. We need to support this too in
4522 // JavaScript.
4523 // In the case of a String object we just need to redirect the assignment to
4524 // the underlying string if the index is in range. Since the underlying
4525 // string does nothing with the assignment then we can ignore such
4526 // assignments.
4527 if (js_object->IsStringObjectWithCharacterAt(index)) {
4528 return *value;
4529 }
4530
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004531 return js_object->SetElement(
4532 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004533 }
4534
4535 if (key->IsString()) {
4536 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004537 return js_object->SetElement(
4538 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004539 } else {
4540 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004541 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004542 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4543 *value,
4544 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004545 }
4546 }
4547
4548 // Call-back into JavaScript to convert the key to a string.
4549 bool has_pending_exception = false;
4550 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4551 if (has_pending_exception) return Failure::Exception();
4552 Handle<String> name = Handle<String>::cast(converted);
4553
4554 if (name->AsArrayIndex(&index)) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00004555 return js_object->SetElement(
4556 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004557 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004558 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004559 }
4560}
4561
4562
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004563MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004564 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004565 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004566 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004567
4568 // Check if the given key is an array index.
4569 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004570 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004571 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4572 // characters of a string using [] notation. In the case of a
4573 // String object we just need to redirect the deletion to the
4574 // underlying string if the index is in range. Since the
4575 // underlying string does nothing with the deletion, we can ignore
4576 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004577 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004578 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004579 }
4580
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004581 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004582 }
4583
4584 Handle<String> key_string;
4585 if (key->IsString()) {
4586 key_string = Handle<String>::cast(key);
4587 } else {
4588 // Call-back into JavaScript to convert the key to a string.
4589 bool has_pending_exception = false;
4590 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4591 if (has_pending_exception) return Failure::Exception();
4592 key_string = Handle<String>::cast(converted);
4593 }
4594
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004595 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004596 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004597}
4598
4599
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004600RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004601 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004602 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603
4604 Handle<Object> object = args.at<Object>(0);
4605 Handle<Object> key = args.at<Object>(1);
4606 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004607 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004608 RUNTIME_ASSERT(
4609 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004610 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004611 PropertyAttributes attributes =
4612 static_cast<PropertyAttributes>(unchecked_attributes);
4613
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004614 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004615 if (args.length() == 5) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004616 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_flag, 4);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004617 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004618 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004619
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004620 return Runtime::SetObjectProperty(isolate,
4621 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004622 key,
4623 value,
4624 attributes,
4625 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004626}
4627
4628
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004629RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4630 NoHandleAllocation ha;
4631 RUNTIME_ASSERT(args.length() == 1);
4632 Handle<Object> object = args.at<Object>(0);
4633 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4634}
4635
4636
4637RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4638 NoHandleAllocation ha;
4639 RUNTIME_ASSERT(args.length() == 1);
4640 Handle<Object> object = args.at<Object>(0);
4641 return TransitionElements(object, FAST_ELEMENTS, isolate);
4642}
4643
4644
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004645// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004646// This is used to decide if we should transform null and undefined
4647// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004648RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004649 NoHandleAllocation ha;
4650 RUNTIME_ASSERT(args.length() == 1);
4651
4652 Handle<Object> object = args.at<Object>(0);
4653
4654 if (object->IsJSFunction()) {
4655 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004656 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004657 }
4658 return isolate->heap()->undefined_value();
4659}
4660
4661
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004662RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4663 RUNTIME_ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004664 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004665 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4666 Handle<Object> value = args.at<Object>(2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004667 CONVERT_ARG_HANDLE_CHECKED(FixedArray, literals, 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004668 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4669 HandleScope scope;
4670
4671 Object* raw_boilerplate_object = literals->get(literal_index);
4672 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4673#if DEBUG
4674 ElementsKind elements_kind = object->GetElementsKind();
4675#endif
4676 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4677 // Smis should never trigger transitions.
4678 ASSERT(!value->IsSmi());
4679
4680 if (value->IsNumber()) {
4681 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004682 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4683 JSObject::TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004684 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4685 FixedDoubleArray* double_array =
4686 FixedDoubleArray::cast(object->elements());
4687 HeapNumber* number = HeapNumber::cast(*value);
4688 double_array->set(store_index, number->Number());
4689 } else {
4690 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4691 elements_kind == FAST_DOUBLE_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004692 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
4693 JSObject::TransitionElementsKind(boilerplate_object, FAST_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004694 FixedArray* object_array =
4695 FixedArray::cast(object->elements());
4696 object_array->set(store_index, *value);
4697 }
4698 return *object;
4699}
4700
4701
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004702// Set a local property, even if it is READ_ONLY. If the property does not
4703// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004704RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004705 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004706 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004707 CONVERT_ARG_CHECKED(JSObject, object, 0);
4708 CONVERT_ARG_CHECKED(String, name, 1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004709 // Compute attributes.
4710 PropertyAttributes attributes = NONE;
4711 if (args.length() == 4) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004712 CONVERT_SMI_ARG_CHECKED(unchecked_value, 3);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004713 // Only attribute bits should be set.
4714 RUNTIME_ASSERT(
4715 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4716 attributes = static_cast<PropertyAttributes>(unchecked_value);
4717 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004718
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004719 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004720 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004721}
4722
4723
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004724RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004725 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004726 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004727
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004728 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4729 CONVERT_ARG_CHECKED(String, key, 1);
4730 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004731 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004732 ? JSReceiver::STRICT_DELETION
4733 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004734}
4735
4736
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004737static Object* HasLocalPropertyImplementation(Isolate* isolate,
4738 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004739 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004740 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004741 // Handle hidden prototypes. If there's a hidden prototype above this thing
4742 // then we have to check it for properties, because they are supposed to
4743 // look like they are on this object.
4744 Handle<Object> proto(object->GetPrototype());
4745 if (proto->IsJSObject() &&
4746 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004747 return HasLocalPropertyImplementation(isolate,
4748 Handle<JSObject>::cast(proto),
4749 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004750 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004751 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004752}
4753
4754
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004755RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004756 NoHandleAllocation ha;
4757 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004758 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004759
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004760 uint32_t index;
4761 const bool key_is_array_index = key->AsArrayIndex(&index);
4762
ager@chromium.org9085a012009-05-11 19:22:57 +00004763 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004764 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004765 if (obj->IsJSObject()) {
4766 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004767 // Fast case: either the key is a real named property or it is not
4768 // an array index and there are no interceptors or hidden
4769 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004770 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004771 Map* map = object->map();
4772 if (!key_is_array_index &&
4773 !map->has_named_interceptor() &&
4774 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4775 return isolate->heap()->false_value();
4776 }
4777 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004778 HandleScope scope(isolate);
4779 return HasLocalPropertyImplementation(isolate,
4780 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004781 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004782 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004783 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004784 String* string = String::cast(obj);
4785 if (index < static_cast<uint32_t>(string->length())) {
4786 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004787 }
4788 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004789 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004790}
4791
4792
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004793RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004794 NoHandleAllocation na;
4795 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004796 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4797 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004798
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004799 bool result = receiver->HasProperty(key);
4800 if (isolate->has_pending_exception()) return Failure::Exception();
4801 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004802}
4803
4804
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004805RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004806 NoHandleAllocation na;
4807 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004808 CONVERT_ARG_CHECKED(JSReceiver, receiver, 0);
4809 CONVERT_SMI_ARG_CHECKED(index, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004810
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004811 bool result = receiver->HasElement(index);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004812 if (isolate->has_pending_exception()) return Failure::Exception();
4813 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004814}
4815
4816
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004817RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004818 NoHandleAllocation ha;
4819 ASSERT(args.length() == 2);
4820
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004821 CONVERT_ARG_CHECKED(JSObject, object, 0);
4822 CONVERT_ARG_CHECKED(String, key, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004823
4824 uint32_t index;
4825 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004826 JSObject::LocalElementType type = object->HasLocalElement(index);
4827 switch (type) {
4828 case JSObject::UNDEFINED_ELEMENT:
4829 case JSObject::STRING_CHARACTER_ELEMENT:
4830 return isolate->heap()->false_value();
4831 case JSObject::INTERCEPTED_ELEMENT:
4832 case JSObject::FAST_ELEMENT:
4833 return isolate->heap()->true_value();
4834 case JSObject::DICTIONARY_ELEMENT: {
4835 if (object->IsJSGlobalProxy()) {
4836 Object* proto = object->GetPrototype();
4837 if (proto->IsNull()) {
4838 return isolate->heap()->false_value();
4839 }
4840 ASSERT(proto->IsJSGlobalObject());
4841 object = JSObject::cast(proto);
4842 }
4843 FixedArray* elements = FixedArray::cast(object->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004844 SeededNumberDictionary* dictionary = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004845 if (elements->map() ==
4846 isolate->heap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004847 dictionary = SeededNumberDictionary::cast(elements->get(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004848 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004849 dictionary = SeededNumberDictionary::cast(elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004850 }
4851 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004852 ASSERT(entry != SeededNumberDictionary::kNotFound);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004853 PropertyDetails details = dictionary->DetailsAt(entry);
4854 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4855 }
4856 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004857 }
4858
ager@chromium.org870a0b62008-11-04 11:43:05 +00004859 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004860 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004861}
4862
4863
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004864RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004865 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004866 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004867 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004868 bool threw = false;
4869 Handle<JSArray> result = GetKeysFor(object, &threw);
4870 if (threw) return Failure::Exception();
4871 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004872}
4873
4874
4875// Returns either a FixedArray as Runtime_GetPropertyNames,
4876// or, if the given object has an enum cache that contains
4877// all enumerable properties of the object and its prototypes
4878// have none, the map of the object. This is used to speed up
4879// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004880RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004881 ASSERT(args.length() == 1);
4882
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004883 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004884
4885 if (raw_object->IsSimpleEnum()) return raw_object->map();
4886
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004887 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004888 Handle<JSReceiver> object(raw_object);
4889 bool threw = false;
4890 Handle<FixedArray> content =
4891 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4892 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004893
4894 // Test again, since cache may have been built by preceding call.
4895 if (object->IsSimpleEnum()) return object->map();
4896
4897 return *content;
4898}
4899
4900
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004901// Find the length of the prototype chain that is to to handled as one. If a
4902// prototype object is hidden it is to be viewed as part of the the object it
4903// is prototype for.
4904static int LocalPrototypeChainLength(JSObject* obj) {
4905 int count = 1;
4906 Object* proto = obj->GetPrototype();
4907 while (proto->IsJSObject() &&
4908 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4909 count++;
4910 proto = JSObject::cast(proto)->GetPrototype();
4911 }
4912 return count;
4913}
4914
4915
4916// Return the names of the local named properties.
4917// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004918RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004919 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004920 ASSERT(args.length() == 1);
4921 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004922 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004923 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00004924 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004925
4926 // Skip the global proxy as it has no properties and always delegates to the
4927 // real global object.
4928 if (obj->IsJSGlobalProxy()) {
4929 // Only collect names if access is permitted.
4930 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004931 !isolate->MayNamedAccess(*obj,
4932 isolate->heap()->undefined_value(),
4933 v8::ACCESS_KEYS)) {
4934 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4935 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004936 }
4937 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4938 }
4939
4940 // Find the number of objects making up this.
4941 int length = LocalPrototypeChainLength(*obj);
4942
4943 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004944 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004945 int total_property_count = 0;
4946 Handle<JSObject> jsproto = obj;
4947 for (int i = 0; i < length; i++) {
4948 // Only collect names if access is permitted.
4949 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004950 !isolate->MayNamedAccess(*jsproto,
4951 isolate->heap()->undefined_value(),
4952 v8::ACCESS_KEYS)) {
4953 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4954 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004955 }
4956 int n;
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00004957 n = jsproto->NumberOfLocalProperties();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004958 local_property_count[i] = n;
4959 total_property_count += n;
4960 if (i < length - 1) {
4961 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4962 }
4963 }
4964
4965 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004966 Handle<FixedArray> names =
4967 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004968
4969 // Get the property names.
4970 jsproto = obj;
4971 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004972 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004973 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004974 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4975 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004976 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004977 proto_with_hidden_properties++;
4978 }
4979 if (i < length - 1) {
4980 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4981 }
4982 }
4983
4984 // Filter out name of hidden propeties object.
4985 if (proto_with_hidden_properties > 0) {
4986 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004987 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004988 names->length() - proto_with_hidden_properties);
4989 int dest_pos = 0;
4990 for (int i = 0; i < total_property_count; i++) {
4991 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004992 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004993 continue;
4994 }
4995 names->set(dest_pos++, name);
4996 }
4997 }
4998
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004999 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005000}
5001
5002
5003// Return the names of the local indexed properties.
5004// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005005RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005006 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005007 ASSERT(args.length() == 1);
5008 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005009 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005010 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005011 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005012
5013 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005014 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005015 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005016 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005017}
5018
5019
5020// Return information on whether an object has a named or indexed interceptor.
5021// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005022RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005023 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005024 ASSERT(args.length() == 1);
5025 if (!args[0]->IsJSObject()) {
5026 return Smi::FromInt(0);
5027 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005028 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005029
5030 int result = 0;
5031 if (obj->HasNamedInterceptor()) result |= 2;
5032 if (obj->HasIndexedInterceptor()) result |= 1;
5033
5034 return Smi::FromInt(result);
5035}
5036
5037
5038// Return property names from named interceptor.
5039// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005040RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005041 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005042 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005043 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005044
5045 if (obj->HasNamedInterceptor()) {
5046 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5047 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5048 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005049 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005050}
5051
5052
5053// Return element names from indexed interceptor.
5054// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005055RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005056 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005057 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005058 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005059
5060 if (obj->HasIndexedInterceptor()) {
5061 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5062 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5063 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005064 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005065}
5066
5067
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005068RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005069 ASSERT_EQ(args.length(), 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005070 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005071 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005072 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005073
5074 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005075 // Do access checks before going to the global object.
5076 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005077 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005078 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005079 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5080 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005081 }
5082
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005083 Handle<Object> proto(object->GetPrototype());
5084 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005085 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005086 object = Handle<JSObject>::cast(proto);
5087 }
5088
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005089 bool threw = false;
5090 Handle<FixedArray> contents =
5091 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5092 if (threw) return Failure::Exception();
5093
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005094 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5095 // property array and since the result is mutable we have to create
5096 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005097 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005098 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005099 for (int i = 0; i < length; i++) {
5100 Object* entry = contents->get(i);
5101 if (entry->IsString()) {
5102 copy->set(i, entry);
5103 } else {
5104 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005105 HandleScope scope(isolate);
5106 Handle<Object> entry_handle(entry, isolate);
5107 Handle<Object> entry_str =
5108 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005109 copy->set(i, *entry_str);
5110 }
5111 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005112 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005113}
5114
5115
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005116RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005117 NoHandleAllocation ha;
5118 ASSERT(args.length() == 1);
5119
5120 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005121 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005122 it.AdvanceToArgumentsFrame();
5123 JavaScriptFrame* frame = it.frame();
5124
5125 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005126 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005127
5128 // Try to convert the key to an index. If successful and within
5129 // index return the the argument from the frame.
5130 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005131 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005132 return frame->GetParameter(index);
5133 }
5134
5135 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005136 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005137 bool exception = false;
5138 Handle<Object> converted =
5139 Execution::ToString(args.at<Object>(0), &exception);
5140 if (exception) return Failure::Exception();
5141 Handle<String> key = Handle<String>::cast(converted);
5142
5143 // Try to convert the string key into an array index.
5144 if (key->AsArrayIndex(&index)) {
5145 if (index < n) {
5146 return frame->GetParameter(index);
5147 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005148 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005149 }
5150 }
5151
5152 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005153 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5154 if (key->Equals(isolate->heap()->callee_symbol())) {
5155 Object* function = frame->function();
5156 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005157 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005158 return isolate->Throw(*isolate->factory()->NewTypeError(
5159 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5160 }
5161 return function;
5162 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005163
5164 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005165 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005166}
5167
5168
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005169RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005170 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005171 Object* object = args[0];
5172 return (object->IsJSObject() && !object->IsGlobalObject())
5173 ? JSObject::cast(object)->TransformToFastProperties(0)
5174 : object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005175}
5176
5177
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005178RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005179 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005180 Object* obj = args[0];
5181 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5182 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5183 : obj;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005184}
5185
5186
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005187RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005188 NoHandleAllocation ha;
5189 ASSERT(args.length() == 1);
5190
5191 return args[0]->ToBoolean();
5192}
5193
5194
5195// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5196// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005197RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005198 NoHandleAllocation ha;
5199
5200 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005201 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005202 HeapObject* heap_obj = HeapObject::cast(obj);
5203
5204 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005205 if (heap_obj->map()->is_undetectable()) {
5206 return isolate->heap()->undefined_symbol();
5207 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005208
5209 InstanceType instance_type = heap_obj->map()->instance_type();
5210 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005211 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005212 }
5213
5214 switch (instance_type) {
5215 case ODDBALL_TYPE:
5216 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005217 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005218 }
5219 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005220 return FLAG_harmony_typeof
5221 ? isolate->heap()->null_symbol()
5222 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005223 }
5224 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005225 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005226 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005227 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005228 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005229 default:
5230 // For any kind of object not handled above, the spec rule for
5231 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005232 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005233 }
5234}
5235
5236
lrn@chromium.org25156de2010-04-06 13:10:27 +00005237static bool AreDigits(const char*s, int from, int to) {
5238 for (int i = from; i < to; i++) {
5239 if (s[i] < '0' || s[i] > '9') return false;
5240 }
5241
5242 return true;
5243}
5244
5245
5246static int ParseDecimalInteger(const char*s, int from, int to) {
5247 ASSERT(to - from < 10); // Overflow is not possible.
5248 ASSERT(from < to);
5249 int d = s[from] - '0';
5250
5251 for (int i = from + 1; i < to; i++) {
5252 d = 10 * d + (s[i] - '0');
5253 }
5254
5255 return d;
5256}
5257
5258
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005259RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005260 NoHandleAllocation ha;
5261 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005262 CONVERT_ARG_CHECKED(String, subject, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005263 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005264
5265 // Fast case: short integer or some sorts of junk values.
5266 int len = subject->length();
5267 if (subject->IsSeqAsciiString()) {
5268 if (len == 0) return Smi::FromInt(0);
5269
5270 char const* data = SeqAsciiString::cast(subject)->GetChars();
5271 bool minus = (data[0] == '-');
5272 int start_pos = (minus ? 1 : 0);
5273
5274 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005275 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005276 } else if (data[start_pos] > '9') {
5277 // Fast check for a junk value. A valid string may start from a
5278 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5279 // the 'I' character ('Infinity'). All of that have codes not greater than
5280 // '9' except 'I'.
5281 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005282 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005283 }
5284 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5285 // The maximal/minimal smi has 10 digits. If the string has less digits we
5286 // know it will fit into the smi-data type.
5287 int d = ParseDecimalInteger(data, start_pos, len);
5288 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005289 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005290 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005291 } else if (!subject->HasHashCode() &&
5292 len <= String::kMaxArrayIndexSize &&
5293 (len == 1 || data[0] != '0')) {
5294 // String hash is not calculated yet but all the data are present.
5295 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005296 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005297#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005298 subject->Hash(); // Force hash calculation.
5299 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5300 static_cast<int>(hash));
5301#endif
5302 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005303 }
5304 return Smi::FromInt(d);
5305 }
5306 }
5307
5308 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005309 return isolate->heap()->NumberFromDouble(
5310 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005311}
5312
5313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005314RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005315 NoHandleAllocation ha;
5316 ASSERT(args.length() == 1);
5317
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005318 CONVERT_ARG_CHECKED(JSArray, codes, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005319 int length = Smi::cast(codes->length())->value();
5320
5321 // Check if the string can be ASCII.
5322 int i;
5323 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005324 Object* element;
5325 { MaybeObject* maybe_element = codes->GetElement(i);
5326 // We probably can't get an exception here, but just in order to enforce
5327 // the checking of inputs in the runtime calls we check here.
5328 if (!maybe_element->ToObject(&element)) return maybe_element;
5329 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005330 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5331 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5332 break;
5333 }
5334
lrn@chromium.org303ada72010-10-27 09:33:13 +00005335 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005336 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005337 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005338 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005339 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005340 }
5341
lrn@chromium.org303ada72010-10-27 09:33:13 +00005342 Object* object = NULL;
5343 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005344 String* result = String::cast(object);
5345 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005346 Object* element;
5347 { MaybeObject* maybe_element = codes->GetElement(i);
5348 if (!maybe_element->ToObject(&element)) return maybe_element;
5349 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005350 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005351 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005352 }
5353 return result;
5354}
5355
5356
5357// kNotEscaped is generated by the following:
5358//
5359// #!/bin/perl
5360// for (my $i = 0; $i < 256; $i++) {
5361// print "\n" if $i % 16 == 0;
5362// my $c = chr($i);
5363// my $escaped = 1;
5364// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5365// print $escaped ? "0, " : "1, ";
5366// }
5367
5368
5369static bool IsNotEscaped(uint16_t character) {
5370 // Only for 8 bit characters, the rest are always escaped (in a different way)
5371 ASSERT(character < 256);
5372 static const char kNotEscaped[256] = {
5373 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5374 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5376 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5377 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5378 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5379 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5380 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5381 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5382 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5383 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5384 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5385 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5386 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5387 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5388 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5389 };
5390 return kNotEscaped[character] != 0;
5391}
5392
5393
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005394RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005395 const char hex_chars[] = "0123456789ABCDEF";
5396 NoHandleAllocation ha;
5397 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005398 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005399
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005400 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005401
5402 int escaped_length = 0;
5403 int length = source->length();
5404 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005405 Access<StringInputBuffer> buffer(
5406 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005407 buffer->Reset(source);
5408 while (buffer->has_more()) {
5409 uint16_t character = buffer->GetNext();
5410 if (character >= 256) {
5411 escaped_length += 6;
5412 } else if (IsNotEscaped(character)) {
5413 escaped_length++;
5414 } else {
5415 escaped_length += 3;
5416 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005417 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005418 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005419 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005420 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005421 return Failure::OutOfMemoryException();
5422 }
5423 }
5424 }
5425 // No length change implies no change. Return original string if no change.
5426 if (escaped_length == length) {
5427 return source;
5428 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005429 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005430 { MaybeObject* maybe_o =
5431 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005432 if (!maybe_o->ToObject(&o)) return maybe_o;
5433 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005434 String* destination = String::cast(o);
5435 int dest_position = 0;
5436
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005437 Access<StringInputBuffer> buffer(
5438 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005439 buffer->Rewind();
5440 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005441 uint16_t chr = buffer->GetNext();
5442 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005443 destination->Set(dest_position, '%');
5444 destination->Set(dest_position+1, 'u');
5445 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5446 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5447 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5448 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005449 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005450 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005451 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005452 dest_position++;
5453 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005454 destination->Set(dest_position, '%');
5455 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5456 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005457 dest_position += 3;
5458 }
5459 }
5460 return destination;
5461}
5462
5463
5464static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5465 static const signed char kHexValue['g'] = {
5466 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5467 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5468 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5469 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5470 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5471 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5472 -1, 10, 11, 12, 13, 14, 15 };
5473
5474 if (character1 > 'f') return -1;
5475 int hi = kHexValue[character1];
5476 if (hi == -1) return -1;
5477 if (character2 > 'f') return -1;
5478 int lo = kHexValue[character2];
5479 if (lo == -1) return -1;
5480 return (hi << 4) + lo;
5481}
5482
5483
ager@chromium.org870a0b62008-11-04 11:43:05 +00005484static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005485 int i,
5486 int length,
5487 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005488 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005489 int32_t hi = 0;
5490 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005491 if (character == '%' &&
5492 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005493 source->Get(i + 1) == 'u' &&
5494 (hi = TwoDigitHex(source->Get(i + 2),
5495 source->Get(i + 3))) != -1 &&
5496 (lo = TwoDigitHex(source->Get(i + 4),
5497 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005498 *step = 6;
5499 return (hi << 8) + lo;
5500 } else if (character == '%' &&
5501 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005502 (lo = TwoDigitHex(source->Get(i + 1),
5503 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005504 *step = 3;
5505 return lo;
5506 } else {
5507 *step = 1;
5508 return character;
5509 }
5510}
5511
5512
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005513RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005514 NoHandleAllocation ha;
5515 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005516 CONVERT_ARG_CHECKED(String, source, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005517
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005518 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005519
5520 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005521 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005522
5523 int unescaped_length = 0;
5524 for (int i = 0; i < length; unescaped_length++) {
5525 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005526 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005527 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005528 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005529 i += step;
5530 }
5531
5532 // No length change implies no change. Return original string if no change.
5533 if (unescaped_length == length)
5534 return source;
5535
lrn@chromium.org303ada72010-10-27 09:33:13 +00005536 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005537 { MaybeObject* maybe_o =
5538 ascii ?
5539 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5540 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005541 if (!maybe_o->ToObject(&o)) return maybe_o;
5542 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005543 String* destination = String::cast(o);
5544
5545 int dest_position = 0;
5546 for (int i = 0; i < length; dest_position++) {
5547 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005548 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005549 i += step;
5550 }
5551 return destination;
5552}
5553
5554
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005555static const unsigned int kQuoteTableLength = 128u;
5556
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005557static const int kJsonQuotesCharactersPerEntry = 8;
5558static const char* const JsonQuotes =
5559 "\\u0000 \\u0001 \\u0002 \\u0003 "
5560 "\\u0004 \\u0005 \\u0006 \\u0007 "
5561 "\\b \\t \\n \\u000b "
5562 "\\f \\r \\u000e \\u000f "
5563 "\\u0010 \\u0011 \\u0012 \\u0013 "
5564 "\\u0014 \\u0015 \\u0016 \\u0017 "
5565 "\\u0018 \\u0019 \\u001a \\u001b "
5566 "\\u001c \\u001d \\u001e \\u001f "
5567 " ! \\\" # "
5568 "$ % & ' "
5569 "( ) * + "
5570 ", - . / "
5571 "0 1 2 3 "
5572 "4 5 6 7 "
5573 "8 9 : ; "
5574 "< = > ? "
5575 "@ A B C "
5576 "D E F G "
5577 "H I J K "
5578 "L M N O "
5579 "P Q R S "
5580 "T U V W "
5581 "X Y Z [ "
5582 "\\\\ ] ^ _ "
5583 "` a b c "
5584 "d e f g "
5585 "h i j k "
5586 "l m n o "
5587 "p q r s "
5588 "t u v w "
5589 "x y z { "
5590 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005591
5592
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005593// For a string that is less than 32k characters it should always be
5594// possible to allocate it in new space.
5595static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5596
5597
5598// Doing JSON quoting cannot make the string more than this many times larger.
5599static const int kJsonQuoteWorstCaseBlowup = 6;
5600
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005601static const int kSpaceForQuotesAndComma = 3;
5602static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005603
5604// Covers the entire ASCII range (all other characters are unchanged by JSON
5605// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005606static const byte JsonQuoteLengths[kQuoteTableLength] = {
5607 6, 6, 6, 6, 6, 6, 6, 6,
5608 2, 2, 2, 6, 2, 2, 6, 6,
5609 6, 6, 6, 6, 6, 6, 6, 6,
5610 6, 6, 6, 6, 6, 6, 6, 6,
5611 1, 1, 2, 1, 1, 1, 1, 1,
5612 1, 1, 1, 1, 1, 1, 1, 1,
5613 1, 1, 1, 1, 1, 1, 1, 1,
5614 1, 1, 1, 1, 1, 1, 1, 1,
5615 1, 1, 1, 1, 1, 1, 1, 1,
5616 1, 1, 1, 1, 1, 1, 1, 1,
5617 1, 1, 1, 1, 1, 1, 1, 1,
5618 1, 1, 1, 1, 2, 1, 1, 1,
5619 1, 1, 1, 1, 1, 1, 1, 1,
5620 1, 1, 1, 1, 1, 1, 1, 1,
5621 1, 1, 1, 1, 1, 1, 1, 1,
5622 1, 1, 1, 1, 1, 1, 1, 1,
5623};
5624
5625
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005626template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005627MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005628
5629
5630template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005631MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5632 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005633}
5634
5635
5636template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005637MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5638 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005639}
5640
5641
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005642template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005643static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5644 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005645 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005646 const Char* read_cursor = characters.start();
5647 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005648 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005649 int quoted_length = kSpaceForQuotes;
5650 while (read_cursor < end) {
5651 Char c = *(read_cursor++);
5652 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5653 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005654 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005655 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005656 }
5657 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005658 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5659 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005660 Object* new_object;
5661 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005662 return new_alloc;
5663 }
5664 StringType* new_string = StringType::cast(new_object);
5665
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005666 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005667 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005668 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005669 *(write_cursor++) = '"';
5670
5671 read_cursor = characters.start();
5672 while (read_cursor < end) {
5673 Char c = *(read_cursor++);
5674 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5675 *(write_cursor++) = c;
5676 } else {
5677 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5678 const char* replacement = JsonQuotes +
5679 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5680 for (int i = 0; i < len; i++) {
5681 *write_cursor++ = *replacement++;
5682 }
5683 }
5684 }
5685 *(write_cursor++) = '"';
5686 return new_string;
5687}
5688
5689
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005690template <typename SinkChar, typename SourceChar>
5691static inline SinkChar* WriteQuoteJsonString(
5692 Isolate* isolate,
5693 SinkChar* write_cursor,
5694 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005695 // SinkChar is only char if SourceChar is guaranteed to be char.
5696 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005697 const SourceChar* read_cursor = characters.start();
5698 const SourceChar* end = read_cursor + characters.length();
5699 *(write_cursor++) = '"';
5700 while (read_cursor < end) {
5701 SourceChar c = *(read_cursor++);
5702 if (sizeof(SourceChar) > 1u &&
5703 static_cast<unsigned>(c) >= kQuoteTableLength) {
5704 *(write_cursor++) = static_cast<SinkChar>(c);
5705 } else {
5706 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5707 const char* replacement = JsonQuotes +
5708 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5709 write_cursor[0] = replacement[0];
5710 if (len > 1) {
5711 write_cursor[1] = replacement[1];
5712 if (len > 2) {
5713 ASSERT(len == 6);
5714 write_cursor[2] = replacement[2];
5715 write_cursor[3] = replacement[3];
5716 write_cursor[4] = replacement[4];
5717 write_cursor[5] = replacement[5];
5718 }
5719 }
5720 write_cursor += len;
5721 }
5722 }
5723 *(write_cursor++) = '"';
5724 return write_cursor;
5725}
5726
5727
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005728template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005729static MaybeObject* QuoteJsonString(Isolate* isolate,
5730 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005731 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005732 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005733 int worst_case_length =
5734 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005735 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005736 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005737 }
5738
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005739 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5740 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005741 Object* new_object;
5742 if (!new_alloc->ToObject(&new_object)) {
5743 return new_alloc;
5744 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005745 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005746 // Even if our string is small enough to fit in new space we still have to
5747 // handle it being allocated in old space as may happen in the third
5748 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5749 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005750 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005751 }
5752 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005753 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005754
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005755 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005756 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005757 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005758 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5759 write_cursor,
5760 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005761 int final_length = static_cast<int>(
5762 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005763 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005764 isolate->heap()->new_space()->
5765 template ShrinkStringAtAllocationBoundary<StringType>(
5766 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005767 return new_string;
5768}
5769
5770
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005771RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005772 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005773 CONVERT_ARG_CHECKED(String, str, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005774 if (!str->IsFlat()) {
5775 MaybeObject* try_flatten = str->TryFlatten();
5776 Object* flat;
5777 if (!try_flatten->ToObject(&flat)) {
5778 return try_flatten;
5779 }
5780 str = String::cast(flat);
5781 ASSERT(str->IsFlat());
5782 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005783 String::FlatContent flat = str->GetFlatContent();
5784 ASSERT(flat.IsFlat());
5785 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005786 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005787 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005788 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005789 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005790 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005791 }
5792}
5793
5794
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005795RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005796 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005797 CONVERT_ARG_CHECKED(String, str, 0);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005798 if (!str->IsFlat()) {
5799 MaybeObject* try_flatten = str->TryFlatten();
5800 Object* flat;
5801 if (!try_flatten->ToObject(&flat)) {
5802 return try_flatten;
5803 }
5804 str = String::cast(flat);
5805 ASSERT(str->IsFlat());
5806 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005807 String::FlatContent flat = str->GetFlatContent();
5808 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005809 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005810 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005811 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005812 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005813 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005814 }
5815}
5816
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005817
5818template <typename Char, typename StringType>
5819static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5820 FixedArray* array,
5821 int worst_case_length) {
5822 int length = array->length();
5823
5824 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5825 worst_case_length);
5826 Object* new_object;
5827 if (!new_alloc->ToObject(&new_object)) {
5828 return new_alloc;
5829 }
5830 if (!isolate->heap()->new_space()->Contains(new_object)) {
5831 // Even if our string is small enough to fit in new space we still have to
5832 // handle it being allocated in old space as may happen in the third
5833 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5834 // CEntryStub::GenerateCore.
5835 return isolate->heap()->undefined_value();
5836 }
5837 AssertNoAllocation no_gc;
5838 StringType* new_string = StringType::cast(new_object);
5839 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5840
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005841 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005842 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005843 *(write_cursor++) = '[';
5844 for (int i = 0; i < length; i++) {
5845 if (i != 0) *(write_cursor++) = ',';
5846 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005847 String::FlatContent content = str->GetFlatContent();
5848 ASSERT(content.IsFlat());
5849 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005850 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5851 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005852 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005853 } else {
5854 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5855 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005856 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005857 }
5858 }
5859 *(write_cursor++) = ']';
5860
5861 int final_length = static_cast<int>(
5862 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005863 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005864 isolate->heap()->new_space()->
5865 template ShrinkStringAtAllocationBoundary<StringType>(
5866 new_string, final_length);
5867 return new_string;
5868}
5869
5870
5871RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5872 NoHandleAllocation ha;
5873 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005874 CONVERT_ARG_CHECKED(JSArray, array, 0);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005875
5876 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5877 FixedArray* elements = FixedArray::cast(array->elements());
5878 int n = elements->length();
5879 bool ascii = true;
5880 int total_length = 0;
5881
5882 for (int i = 0; i < n; i++) {
5883 Object* elt = elements->get(i);
5884 if (!elt->IsString()) return isolate->heap()->undefined_value();
5885 String* element = String::cast(elt);
5886 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5887 total_length += element->length();
5888 if (ascii && element->IsTwoByteRepresentation()) {
5889 ascii = false;
5890 }
5891 }
5892
5893 int worst_case_length =
5894 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5895 + total_length * kJsonQuoteWorstCaseBlowup;
5896
5897 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5898 return isolate->heap()->undefined_value();
5899 }
5900
5901 if (ascii) {
5902 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5903 elements,
5904 worst_case_length);
5905 } else {
5906 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5907 elements,
5908 worst_case_length);
5909 }
5910}
5911
5912
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005913RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005914 NoHandleAllocation ha;
5915
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005916 CONVERT_ARG_CHECKED(String, s, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005917 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005918
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005919 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005920
lrn@chromium.org25156de2010-04-06 13:10:27 +00005921 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005922 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005923 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005924}
5925
5926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005927RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005928 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00005929 CONVERT_ARG_CHECKED(String, str, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005930
5931 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005932 double value = StringToDouble(isolate->unicode_cache(),
5933 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005934
5935 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005936 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005937}
5938
5939
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005940template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005941MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005942 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005943 String* s,
5944 int length,
5945 int input_string_length,
5946 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005947 // We try this twice, once with the assumption that the result is no longer
5948 // than the input and, if that assumption breaks, again with the exact
5949 // length. This may not be pretty, but it is nicer than what was here before
5950 // and I hereby claim my vaffel-is.
5951 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005952 // Allocate the resulting string.
5953 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00005954 // NOTE: This assumes that the upper/lower case of an ASCII
5955 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005956 // might break in the future if we implement more context and locale
5957 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005958 Object* o;
5959 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005960 ? isolate->heap()->AllocateRawAsciiString(length)
5961 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005962 if (!maybe_o->ToObject(&o)) return maybe_o;
5963 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005964 String* result = String::cast(o);
5965 bool has_changed_character = false;
5966
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005967 // Convert all characters to upper case, assuming that they will fit
5968 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005969 Access<StringInputBuffer> buffer(
5970 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005971 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005972 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005973 // We can assume that the string is not empty
5974 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005975 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005976 bool has_next = buffer->has_more();
5977 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005978 int char_length = mapping->get(current, next, chars);
5979 if (char_length == 0) {
5980 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005981 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005982 i++;
5983 } else if (char_length == 1) {
5984 // Common case: converting the letter resulted in one character.
5985 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005986 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005987 has_changed_character = true;
5988 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005989 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005990 // We've assumed that the result would be as long as the
5991 // input but here is a character that converts to several
5992 // characters. No matter, we calculate the exact length
5993 // of the result and try the whole thing again.
5994 //
5995 // Note that this leaves room for optimization. We could just
5996 // memcpy what we already have to the result string. Also,
5997 // the result string is the last object allocated we could
5998 // "realloc" it and probably, in the vast majority of cases,
5999 // extend the existing string to be able to hold the full
6000 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006001 int next_length = 0;
6002 if (has_next) {
6003 next_length = mapping->get(next, 0, chars);
6004 if (next_length == 0) next_length = 1;
6005 }
6006 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006007 while (buffer->has_more()) {
6008 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006009 // NOTE: we use 0 as the next character here because, while
6010 // the next character may affect what a character converts to,
6011 // it does not in any case affect the length of what it convert
6012 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006013 int char_length = mapping->get(current, 0, chars);
6014 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006015 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006016 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006017 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006018 return Failure::OutOfMemoryException();
6019 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006020 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006021 // Try again with the real length.
6022 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006023 } else {
6024 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006025 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006026 i++;
6027 }
6028 has_changed_character = true;
6029 }
6030 current = next;
6031 }
6032 if (has_changed_character) {
6033 return result;
6034 } else {
6035 // If we didn't actually change anything in doing the conversion
6036 // we simple return the result and let the converted string
6037 // become garbage; there is no reason to keep two identical strings
6038 // alive.
6039 return s;
6040 }
6041}
6042
6043
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006044namespace {
6045
lrn@chromium.org303ada72010-10-27 09:33:13 +00006046static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6047
6048
6049// Given a word and two range boundaries returns a word with high bit
6050// set in every byte iff the corresponding input byte was strictly in
6051// the range (m, n). All the other bits in the result are cleared.
6052// This function is only useful when it can be inlined and the
6053// boundaries are statically known.
6054// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006055// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006056static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006057 // Every byte in an ASCII string is less than or equal to 0x7F.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006058 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6059 // Use strict inequalities since in edge cases the function could be
6060 // further simplified.
6061 ASSERT(0 < m && m < n && n < 0x7F);
6062 // Has high bit set in every w byte less than n.
6063 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6064 // Has high bit set in every w byte greater than m.
6065 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6066 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6067}
6068
6069
6070enum AsciiCaseConversion {
6071 ASCII_TO_LOWER,
6072 ASCII_TO_UPPER
6073};
6074
6075
6076template <AsciiCaseConversion dir>
6077struct FastAsciiConverter {
6078 static bool Convert(char* dst, char* src, int length) {
6079#ifdef DEBUG
6080 char* saved_dst = dst;
6081 char* saved_src = src;
6082#endif
6083 // We rely on the distance between upper and lower case letters
6084 // being a known power of 2.
6085 ASSERT('a' - 'A' == (1 << 5));
6086 // Boundaries for the range of input characters than require conversion.
6087 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6088 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6089 bool changed = false;
6090 char* const limit = src + length;
6091#ifdef V8_HOST_CAN_READ_UNALIGNED
6092 // Process the prefix of the input that requires no conversion one
6093 // (machine) word at a time.
6094 while (src <= limit - sizeof(uintptr_t)) {
6095 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6096 if (AsciiRangeMask(w, lo, hi) != 0) {
6097 changed = true;
6098 break;
6099 }
6100 *reinterpret_cast<uintptr_t*>(dst) = w;
6101 src += sizeof(uintptr_t);
6102 dst += sizeof(uintptr_t);
6103 }
6104 // Process the remainder of the input performing conversion when
6105 // required one word at a time.
6106 while (src <= limit - sizeof(uintptr_t)) {
6107 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6108 uintptr_t m = AsciiRangeMask(w, lo, hi);
6109 // The mask has high (7th) bit set in every byte that needs
6110 // conversion and we know that the distance between cases is
6111 // 1 << 5.
6112 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6113 src += sizeof(uintptr_t);
6114 dst += sizeof(uintptr_t);
6115 }
6116#endif
6117 // Process the last few bytes of the input (or the whole input if
6118 // unaligned access is not supported).
6119 while (src < limit) {
6120 char c = *src;
6121 if (lo < c && c < hi) {
6122 c ^= (1 << 5);
6123 changed = true;
6124 }
6125 *dst = c;
6126 ++src;
6127 ++dst;
6128 }
6129#ifdef DEBUG
6130 CheckConvert(saved_dst, saved_src, length, changed);
6131#endif
6132 return changed;
6133 }
6134
6135#ifdef DEBUG
6136 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6137 bool expected_changed = false;
6138 for (int i = 0; i < length; i++) {
6139 if (dst[i] == src[i]) continue;
6140 expected_changed = true;
6141 if (dir == ASCII_TO_LOWER) {
6142 ASSERT('A' <= src[i] && src[i] <= 'Z');
6143 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6144 } else {
6145 ASSERT(dir == ASCII_TO_UPPER);
6146 ASSERT('a' <= src[i] && src[i] <= 'z');
6147 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6148 }
6149 }
6150 ASSERT(expected_changed == changed);
6151 }
6152#endif
6153};
6154
6155
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006156struct ToLowerTraits {
6157 typedef unibrow::ToLowercase UnibrowConverter;
6158
lrn@chromium.org303ada72010-10-27 09:33:13 +00006159 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006160};
6161
6162
6163struct ToUpperTraits {
6164 typedef unibrow::ToUppercase UnibrowConverter;
6165
lrn@chromium.org303ada72010-10-27 09:33:13 +00006166 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006167};
6168
6169} // namespace
6170
6171
6172template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006173MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006174 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006175 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006176 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006177 NoHandleAllocation ha;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006178 CONVERT_ARG_CHECKED(String, s, 0);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006179 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006180
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006181 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006182 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006183 if (length == 0) return s;
6184
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006185 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006186 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006187 // NOTE: This assumes that the upper/lower case of an ASCII
6188 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006189 // might break in the future if we implement more context and locale
6190 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006191 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006192 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006193 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006194 if (!maybe_o->ToObject(&o)) return maybe_o;
6195 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006196 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006197 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006198 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006199 return has_changed_character ? result : s;
6200 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006201
lrn@chromium.org303ada72010-10-27 09:33:13 +00006202 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006203 { MaybeObject* maybe_answer =
6204 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006205 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6206 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006207 if (answer->IsSmi()) {
6208 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006209 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006210 ConvertCaseHelper(isolate,
6211 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006212 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6213 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006214 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006215 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006216}
6217
6218
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006219RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006220 return ConvertCase<ToLowerTraits>(
6221 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006222}
6223
6224
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006225RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006226 return ConvertCase<ToUpperTraits>(
6227 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006228}
6229
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006230
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006231static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006232 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006233}
6234
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006235
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006236RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006237 NoHandleAllocation ha;
6238 ASSERT(args.length() == 3);
6239
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006240 CONVERT_ARG_CHECKED(String, s, 0);
6241 CONVERT_BOOLEAN_ARG_CHECKED(trimLeft, 1);
6242 CONVERT_BOOLEAN_ARG_CHECKED(trimRight, 2);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006243
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006244 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006245 int length = s->length();
6246
6247 int left = 0;
6248 if (trimLeft) {
6249 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6250 left++;
6251 }
6252 }
6253
6254 int right = length;
6255 if (trimRight) {
6256 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6257 right--;
6258 }
6259 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006260 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006261}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006262
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006263
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006264RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006265 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006266 HandleScope handle_scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006267 CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);
6268 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 1);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006269 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6270
6271 int subject_length = subject->length();
6272 int pattern_length = pattern->length();
6273 RUNTIME_ASSERT(pattern_length > 0);
6274
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006275 if (limit == 0xffffffffu) {
6276 Handle<Object> cached_answer(StringSplitCache::Lookup(
6277 isolate->heap()->string_split_cache(),
6278 *subject,
6279 *pattern));
6280 if (*cached_answer != Smi::FromInt(0)) {
6281 Handle<JSArray> result =
6282 isolate->factory()->NewJSArrayWithElements(
6283 Handle<FixedArray>::cast(cached_answer));
6284 return *result;
6285 }
6286 }
6287
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006288 // The limit can be very large (0xffffffffu), but since the pattern
6289 // isn't empty, we can never create more parts than ~half the length
6290 // of the subject.
6291
6292 if (!subject->IsFlat()) FlattenString(subject);
6293
6294 static const int kMaxInitialListCapacity = 16;
6295
danno@chromium.org40cb8782011-05-25 07:58:50 +00006296 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006297
6298 // Find (up to limit) indices of separator and end-of-string in subject
6299 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6300 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006301 if (!pattern->IsFlat()) FlattenString(pattern);
6302
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006303 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006304
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006305 if (static_cast<uint32_t>(indices.length()) < limit) {
6306 indices.Add(subject_length);
6307 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006308
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006309 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006310
6311 // Create JSArray of substrings separated by separator.
6312 int part_count = indices.length();
6313
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006314 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006315 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006316 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006317 result->set_length(Smi::FromInt(part_count));
6318
6319 ASSERT(result->HasFastElements());
6320
6321 if (part_count == 1 && indices.at(0) == subject_length) {
6322 FixedArray::cast(result->elements())->set(0, *subject);
6323 return *result;
6324 }
6325
6326 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6327 int part_start = 0;
6328 for (int i = 0; i < part_count; i++) {
6329 HandleScope local_loop_handle;
6330 int part_end = indices.at(i);
6331 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006332 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006333 elements->set(i, *substring);
6334 part_start = part_end + pattern_length;
6335 }
6336
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006337 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006338 if (result->HasFastElements()) {
6339 StringSplitCache::Enter(isolate->heap(),
6340 isolate->heap()->string_split_cache(),
6341 *subject,
6342 *pattern,
6343 *elements);
6344 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006345 }
6346
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006347 return *result;
6348}
6349
6350
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006351// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006352// one-char strings in the cache. Gives up on the first char that is
6353// not in the cache and fills the remainder with smi zeros. Returns
6354// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006355static int CopyCachedAsciiCharsToArray(Heap* heap,
6356 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006357 FixedArray* elements,
6358 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006359 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006360 FixedArray* ascii_cache = heap->single_character_string_cache();
6361 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006362 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006363 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006364 for (i = 0; i < length; ++i) {
6365 Object* value = ascii_cache->get(chars[i]);
6366 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006367 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006368 }
6369 if (i < length) {
6370 ASSERT(Smi::FromInt(0) == 0);
6371 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6372 }
6373#ifdef DEBUG
6374 for (int j = 0; j < length; ++j) {
6375 Object* element = elements->get(j);
6376 ASSERT(element == Smi::FromInt(0) ||
6377 (element->IsString() && String::cast(element)->LooksValid()));
6378 }
6379#endif
6380 return i;
6381}
6382
6383
6384// Converts a String to JSArray.
6385// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006386RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006387 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006388 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006389 CONVERT_ARG_HANDLE_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006390 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006391
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006392 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006393 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006394
6395 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006396 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006397 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006398 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006399 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006400 { MaybeObject* maybe_obj =
6401 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006402 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6403 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006404 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006405 String::FlatContent content = s->GetFlatContent();
6406 if (content.IsAscii()) {
6407 Vector<const char> chars = content.ToAsciiVector();
6408 // Note, this will initialize all elements (not only the prefix)
6409 // to prevent GC from seeing partially initialized array.
6410 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6411 chars.start(),
6412 *elements,
6413 length);
6414 } else {
6415 MemsetPointer(elements->data_start(),
6416 isolate->heap()->undefined_value(),
6417 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006418 }
6419 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006420 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006421 }
6422 for (int i = position; i < length; ++i) {
6423 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6424 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006425 }
6426
6427#ifdef DEBUG
6428 for (int i = 0; i < length; ++i) {
6429 ASSERT(String::cast(elements->get(i))->length() == 1);
6430 }
6431#endif
6432
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006433 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006434}
6435
6436
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006437RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006438 NoHandleAllocation ha;
6439 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006440 CONVERT_ARG_CHECKED(String, value, 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006441 return value->ToObject();
6442}
6443
6444
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006445bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006446 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006447 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006448 return char_length == 0;
6449}
6450
6451
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006452RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006453 NoHandleAllocation ha;
6454 ASSERT(args.length() == 1);
6455
6456 Object* number = args[0];
6457 RUNTIME_ASSERT(number->IsNumber());
6458
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006459 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006460}
6461
6462
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006463RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006464 NoHandleAllocation ha;
6465 ASSERT(args.length() == 1);
6466
6467 Object* number = args[0];
6468 RUNTIME_ASSERT(number->IsNumber());
6469
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006470 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006471}
6472
6473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006474RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006475 NoHandleAllocation ha;
6476 ASSERT(args.length() == 1);
6477
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006478 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006479
6480 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6481 if (number > 0 && number <= Smi::kMaxValue) {
6482 return Smi::FromInt(static_cast<int>(number));
6483 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006484 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006485}
6486
6487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006488RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006489 NoHandleAllocation ha;
6490 ASSERT(args.length() == 1);
6491
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006492 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006493
6494 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6495 if (number > 0 && number <= Smi::kMaxValue) {
6496 return Smi::FromInt(static_cast<int>(number));
6497 }
6498
6499 double double_value = DoubleToInteger(number);
6500 // Map both -0 and +0 to +0.
6501 if (double_value == 0) double_value = 0;
6502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006503 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006504}
6505
6506
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006507RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006508 NoHandleAllocation ha;
6509 ASSERT(args.length() == 1);
6510
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006511 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006512 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006513}
6514
6515
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006516RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006517 NoHandleAllocation ha;
6518 ASSERT(args.length() == 1);
6519
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006520 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006521
6522 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6523 if (number > 0 && number <= Smi::kMaxValue) {
6524 return Smi::FromInt(static_cast<int>(number));
6525 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006526 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006527}
6528
6529
ager@chromium.org870a0b62008-11-04 11:43:05 +00006530// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6531// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006532RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006533 NoHandleAllocation ha;
6534 ASSERT(args.length() == 1);
6535
6536 Object* obj = args[0];
6537 if (obj->IsSmi()) {
6538 return obj;
6539 }
6540 if (obj->IsHeapNumber()) {
6541 double value = HeapNumber::cast(obj)->value();
6542 int int_value = FastD2I(value);
6543 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6544 return Smi::FromInt(int_value);
6545 }
6546 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006547 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006548}
6549
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006551RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006552 NoHandleAllocation ha;
6553 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006554 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006555}
6556
6557
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006558RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006559 NoHandleAllocation ha;
6560 ASSERT(args.length() == 2);
6561
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006562 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6563 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006564 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006565}
6566
6567
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006568RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006569 NoHandleAllocation ha;
6570 ASSERT(args.length() == 2);
6571
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006572 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6573 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006574 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006575}
6576
6577
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006578RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006579 NoHandleAllocation ha;
6580 ASSERT(args.length() == 2);
6581
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006582 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6583 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006584 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006585}
6586
6587
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006588RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006589 NoHandleAllocation ha;
6590 ASSERT(args.length() == 1);
6591
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006592 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006593 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006594}
6595
6596
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006597RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006598 NoHandleAllocation ha;
6599 ASSERT(args.length() == 0);
6600
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006601 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006602}
6603
6604
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006605RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006606 NoHandleAllocation ha;
6607 ASSERT(args.length() == 2);
6608
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006609 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6610 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006611 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006612}
6613
6614
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006615RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006616 NoHandleAllocation ha;
6617 ASSERT(args.length() == 2);
6618
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006619 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6620 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006621
ager@chromium.org3811b432009-10-28 14:53:37 +00006622 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006623 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006624 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006625}
6626
6627
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006628RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006629 NoHandleAllocation ha;
6630 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006631 CONVERT_ARG_CHECKED(String, str1, 0);
6632 CONVERT_ARG_CHECKED(String, str2, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006633 isolate->counters()->string_add_runtime()->Increment();
6634 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006635}
6636
6637
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006638template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006639static inline void StringBuilderConcatHelper(String* special,
6640 sinkchar* sink,
6641 FixedArray* fixed_array,
6642 int array_length) {
6643 int position = 0;
6644 for (int i = 0; i < array_length; i++) {
6645 Object* element = fixed_array->get(i);
6646 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006647 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006648 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006649 int pos;
6650 int len;
6651 if (encoded_slice > 0) {
6652 // Position and length encoded in one smi.
6653 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6654 len = StringBuilderSubstringLength::decode(encoded_slice);
6655 } else {
6656 // Position and length encoded in two smis.
6657 Object* obj = fixed_array->get(++i);
6658 ASSERT(obj->IsSmi());
6659 pos = Smi::cast(obj)->value();
6660 len = -encoded_slice;
6661 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006662 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006663 sink + position,
6664 pos,
6665 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006666 position += len;
6667 } else {
6668 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006669 int element_length = string->length();
6670 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006671 position += element_length;
6672 }
6673 }
6674}
6675
6676
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006677RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006678 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006679 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006680 CONVERT_ARG_CHECKED(JSArray, array, 0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006681 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006682 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006683 return Failure::OutOfMemoryException();
6684 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006685 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006686 CONVERT_ARG_CHECKED(String, special, 2);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006687
6688 // This assumption is used by the slice encoding in one or two smis.
6689 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6690
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006691 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006692 if (maybe_result->IsFailure()) return maybe_result;
6693
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006694 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006695 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006696 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006697 }
6698 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006699 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006700 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006701 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006702
6703 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006704 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006705 } else if (array_length == 1) {
6706 Object* first = fixed_array->get(0);
6707 if (first->IsString()) return first;
6708 }
6709
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006710 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006711 int position = 0;
6712 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006713 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006714 Object* elt = fixed_array->get(i);
6715 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006716 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006717 int smi_value = Smi::cast(elt)->value();
6718 int pos;
6719 int len;
6720 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006721 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006722 pos = StringBuilderSubstringPosition::decode(smi_value);
6723 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006724 } else {
6725 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006726 len = -smi_value;
6727 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006728 i++;
6729 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006730 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006731 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006732 Object* next_smi = fixed_array->get(i);
6733 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006734 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006735 }
6736 pos = Smi::cast(next_smi)->value();
6737 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006738 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006739 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006740 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006741 ASSERT(pos >= 0);
6742 ASSERT(len >= 0);
6743 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006744 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006745 }
6746 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006747 } else if (elt->IsString()) {
6748 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006749 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006750 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006751 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006752 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006753 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006754 } else {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00006755 ASSERT(!elt->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006756 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006757 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006758 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006759 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006760 return Failure::OutOfMemoryException();
6761 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006762 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006763 }
6764
6765 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006766 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006767
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006768 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006769 { MaybeObject* maybe_object =
6770 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006771 if (!maybe_object->ToObject(&object)) return maybe_object;
6772 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006773 SeqAsciiString* answer = SeqAsciiString::cast(object);
6774 StringBuilderConcatHelper(special,
6775 answer->GetChars(),
6776 fixed_array,
6777 array_length);
6778 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006779 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006780 { MaybeObject* maybe_object =
6781 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006782 if (!maybe_object->ToObject(&object)) return maybe_object;
6783 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006784 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6785 StringBuilderConcatHelper(special,
6786 answer->GetChars(),
6787 fixed_array,
6788 array_length);
6789 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006790 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006791}
6792
6793
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006794RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006795 NoHandleAllocation ha;
6796 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006797 CONVERT_ARG_CHECKED(JSArray, array, 0);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006798 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006799 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006800 return Failure::OutOfMemoryException();
6801 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006802 int array_length = args.smi_at(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006803 CONVERT_ARG_CHECKED(String, separator, 2);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006804
6805 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006806 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006807 }
6808 FixedArray* fixed_array = FixedArray::cast(array->elements());
6809 if (fixed_array->length() < array_length) {
6810 array_length = fixed_array->length();
6811 }
6812
6813 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006814 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006815 } else if (array_length == 1) {
6816 Object* first = fixed_array->get(0);
6817 if (first->IsString()) return first;
6818 }
6819
6820 int separator_length = separator->length();
6821 int max_nof_separators =
6822 (String::kMaxLength + separator_length - 1) / separator_length;
6823 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006824 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006825 return Failure::OutOfMemoryException();
6826 }
6827 int length = (array_length - 1) * separator_length;
6828 for (int i = 0; i < array_length; i++) {
6829 Object* element_obj = fixed_array->get(i);
6830 if (!element_obj->IsString()) {
6831 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006832 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006833 }
6834 String* element = String::cast(element_obj);
6835 int increment = element->length();
6836 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006837 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006838 return Failure::OutOfMemoryException();
6839 }
6840 length += increment;
6841 }
6842
6843 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006844 { MaybeObject* maybe_object =
6845 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006846 if (!maybe_object->ToObject(&object)) return maybe_object;
6847 }
6848 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6849
6850 uc16* sink = answer->GetChars();
6851#ifdef DEBUG
6852 uc16* end = sink + length;
6853#endif
6854
6855 String* first = String::cast(fixed_array->get(0));
6856 int first_length = first->length();
6857 String::WriteToFlat(first, sink, 0, first_length);
6858 sink += first_length;
6859
6860 for (int i = 1; i < array_length; i++) {
6861 ASSERT(sink + separator_length <= end);
6862 String::WriteToFlat(separator, sink, 0, separator_length);
6863 sink += separator_length;
6864
6865 String* element = String::cast(fixed_array->get(i));
6866 int element_length = element->length();
6867 ASSERT(sink + element_length <= end);
6868 String::WriteToFlat(element, sink, 0, element_length);
6869 sink += element_length;
6870 }
6871 ASSERT(sink == end);
6872
6873 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6874 return answer;
6875}
6876
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006877template <typename Char>
6878static void JoinSparseArrayWithSeparator(FixedArray* elements,
6879 int elements_length,
6880 uint32_t array_length,
6881 String* separator,
6882 Vector<Char> buffer) {
6883 int previous_separator_position = 0;
6884 int separator_length = separator->length();
6885 int cursor = 0;
6886 for (int i = 0; i < elements_length; i += 2) {
6887 int position = NumberToInt32(elements->get(i));
6888 String* string = String::cast(elements->get(i + 1));
6889 int string_length = string->length();
6890 if (string->length() > 0) {
6891 while (previous_separator_position < position) {
6892 String::WriteToFlat<Char>(separator, &buffer[cursor],
6893 0, separator_length);
6894 cursor += separator_length;
6895 previous_separator_position++;
6896 }
6897 String::WriteToFlat<Char>(string, &buffer[cursor],
6898 0, string_length);
6899 cursor += string->length();
6900 }
6901 }
6902 if (separator_length > 0) {
6903 // Array length must be representable as a signed 32-bit number,
6904 // otherwise the total string length would have been too large.
6905 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6906 int last_array_index = static_cast<int>(array_length - 1);
6907 while (previous_separator_position < last_array_index) {
6908 String::WriteToFlat<Char>(separator, &buffer[cursor],
6909 0, separator_length);
6910 cursor += separator_length;
6911 previous_separator_position++;
6912 }
6913 }
6914 ASSERT(cursor <= buffer.length());
6915}
6916
6917
6918RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6919 NoHandleAllocation ha;
6920 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006921 CONVERT_ARG_CHECKED(JSArray, elements_array, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006922 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6923 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006924 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006925 CONVERT_ARG_CHECKED(String, separator, 2);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006926 // elements_array is fast-mode JSarray of alternating positions
6927 // (increasing order) and strings.
6928 // array_length is length of original array (used to add separators);
6929 // separator is string to put between elements. Assumed to be non-empty.
6930
6931 // Find total length of join result.
6932 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006933 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006934 int max_string_length;
6935 if (is_ascii) {
6936 max_string_length = SeqAsciiString::kMaxLength;
6937 } else {
6938 max_string_length = SeqTwoByteString::kMaxLength;
6939 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006940 bool overflow = false;
6941 CONVERT_NUMBER_CHECKED(int, elements_length,
6942 Int32, elements_array->length());
6943 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6944 FixedArray* elements = FixedArray::cast(elements_array->elements());
6945 for (int i = 0; i < elements_length; i += 2) {
6946 RUNTIME_ASSERT(elements->get(i)->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00006947 RUNTIME_ASSERT(elements->get(i + 1)->IsString());
6948 String* string = String::cast(elements->get(i + 1));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006949 int length = string->length();
6950 if (is_ascii && !string->IsAsciiRepresentation()) {
6951 is_ascii = false;
6952 max_string_length = SeqTwoByteString::kMaxLength;
6953 }
6954 if (length > max_string_length ||
6955 max_string_length - length < string_length) {
6956 overflow = true;
6957 break;
6958 }
6959 string_length += length;
6960 }
6961 int separator_length = separator->length();
6962 if (!overflow && separator_length > 0) {
6963 if (array_length <= 0x7fffffffu) {
6964 int separator_count = static_cast<int>(array_length) - 1;
6965 int remaining_length = max_string_length - string_length;
6966 if ((remaining_length / separator_length) >= separator_count) {
6967 string_length += separator_length * (array_length - 1);
6968 } else {
6969 // Not room for the separators within the maximal string length.
6970 overflow = true;
6971 }
6972 } else {
6973 // Nonempty separator and at least 2^31-1 separators necessary
6974 // means that the string is too large to create.
6975 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6976 overflow = true;
6977 }
6978 }
6979 if (overflow) {
6980 // Throw OutOfMemory exception for creating too large a string.
6981 V8::FatalProcessOutOfMemory("Array join result too large.");
6982 }
6983
6984 if (is_ascii) {
6985 MaybeObject* result_allocation =
6986 isolate->heap()->AllocateRawAsciiString(string_length);
6987 if (result_allocation->IsFailure()) return result_allocation;
6988 SeqAsciiString* result_string =
6989 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6990 JoinSparseArrayWithSeparator<char>(elements,
6991 elements_length,
6992 array_length,
6993 separator,
6994 Vector<char>(result_string->GetChars(),
6995 string_length));
6996 return result_string;
6997 } else {
6998 MaybeObject* result_allocation =
6999 isolate->heap()->AllocateRawTwoByteString(string_length);
7000 if (result_allocation->IsFailure()) return result_allocation;
7001 SeqTwoByteString* result_string =
7002 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7003 JoinSparseArrayWithSeparator<uc16>(elements,
7004 elements_length,
7005 array_length,
7006 separator,
7007 Vector<uc16>(result_string->GetChars(),
7008 string_length));
7009 return result_string;
7010 }
7011}
7012
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007014RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007015 NoHandleAllocation ha;
7016 ASSERT(args.length() == 2);
7017
7018 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7019 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007020 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007021}
7022
7023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007024RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007025 NoHandleAllocation ha;
7026 ASSERT(args.length() == 2);
7027
7028 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7029 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007030 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007031}
7032
7033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007034RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007035 NoHandleAllocation ha;
7036 ASSERT(args.length() == 2);
7037
7038 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7039 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007040 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007041}
7042
7043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007044RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007045 NoHandleAllocation ha;
7046 ASSERT(args.length() == 1);
7047
7048 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007049 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007050}
7051
7052
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007053RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007054 NoHandleAllocation ha;
7055 ASSERT(args.length() == 2);
7056
7057 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7058 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007059 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007060}
7061
7062
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007063RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007064 NoHandleAllocation ha;
7065 ASSERT(args.length() == 2);
7066
7067 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7068 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007069 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007070}
7071
7072
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007073RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007074 NoHandleAllocation ha;
7075 ASSERT(args.length() == 2);
7076
7077 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7078 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007079 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007080}
7081
7082
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007083RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007084 NoHandleAllocation ha;
7085 ASSERT(args.length() == 2);
7086
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007087 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7088 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007089 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7090 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7091 if (x == y) return Smi::FromInt(EQUAL);
7092 Object* result;
7093 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7094 result = Smi::FromInt(EQUAL);
7095 } else {
7096 result = Smi::FromInt(NOT_EQUAL);
7097 }
7098 return result;
7099}
7100
7101
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007102RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007103 NoHandleAllocation ha;
7104 ASSERT(args.length() == 2);
7105
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007106 CONVERT_ARG_CHECKED(String, x, 0);
7107 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007108
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007109 bool not_equal = !x->Equals(y);
7110 // This is slightly convoluted because the value that signifies
7111 // equality is 0 and inequality is 1 so we have to negate the result
7112 // from String::Equals.
7113 ASSERT(not_equal == 0 || not_equal == 1);
7114 STATIC_CHECK(EQUAL == 0);
7115 STATIC_CHECK(NOT_EQUAL == 1);
7116 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007117}
7118
7119
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007120RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007121 NoHandleAllocation ha;
7122 ASSERT(args.length() == 3);
7123
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007124 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7125 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007126 if (isnan(x) || isnan(y)) return args[2];
7127 if (x == y) return Smi::FromInt(EQUAL);
7128 if (isless(x, y)) return Smi::FromInt(LESS);
7129 return Smi::FromInt(GREATER);
7130}
7131
7132
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007133// Compare two Smis as if they were converted to strings and then
7134// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007135RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007136 NoHandleAllocation ha;
7137 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007138 CONVERT_SMI_ARG_CHECKED(x_value, 0);
7139 CONVERT_SMI_ARG_CHECKED(y_value, 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007140
7141 // If the integers are equal so are the string representations.
7142 if (x_value == y_value) return Smi::FromInt(EQUAL);
7143
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007144 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007145 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007146 if (x_value == 0 || y_value == 0)
7147 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007148
ager@chromium.org32912102009-01-16 10:38:43 +00007149 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007150 // smallest because the char code of '-' is less than the char code
7151 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007152
7153 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7154 // architectures using 32-bit Smis.
7155 uint32_t x_scaled = x_value;
7156 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007157 if (x_value < 0 || y_value < 0) {
7158 if (y_value >= 0) return Smi::FromInt(LESS);
7159 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007160 x_scaled = -x_value;
7161 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007162 }
7163
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007164 static const uint32_t kPowersOf10[] = {
7165 1, 10, 100, 1000, 10*1000, 100*1000,
7166 1000*1000, 10*1000*1000, 100*1000*1000,
7167 1000*1000*1000
7168 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007169
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007170 // If the integers have the same number of decimal digits they can be
7171 // compared directly as the numeric order is the same as the
7172 // lexicographic order. If one integer has fewer digits, it is scaled
7173 // by some power of 10 to have the same number of digits as the longer
7174 // integer. If the scaled integers are equal it means the shorter
7175 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007176
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007177 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7178 int x_log2 = IntegerLog2(x_scaled);
7179 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7180 x_log10 -= x_scaled < kPowersOf10[x_log10];
7181
7182 int y_log2 = IntegerLog2(y_scaled);
7183 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7184 y_log10 -= y_scaled < kPowersOf10[y_log10];
7185
7186 int tie = EQUAL;
7187
7188 if (x_log10 < y_log10) {
7189 // X has fewer digits. We would like to simply scale up X but that
7190 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7191 // be scaled up to 9_000_000_000. So we scale up by the next
7192 // smallest power and scale down Y to drop one digit. It is OK to
7193 // drop one digit from the longer integer since the final digit is
7194 // past the length of the shorter integer.
7195 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7196 y_scaled /= 10;
7197 tie = LESS;
7198 } else if (y_log10 < x_log10) {
7199 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7200 x_scaled /= 10;
7201 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007202 }
7203
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007204 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7205 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7206 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007207}
7208
7209
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007210static Object* StringInputBufferCompare(RuntimeState* state,
7211 String* x,
7212 String* y) {
7213 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7214 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007215 bufx.Reset(x);
7216 bufy.Reset(y);
7217 while (bufx.has_more() && bufy.has_more()) {
7218 int d = bufx.GetNext() - bufy.GetNext();
7219 if (d < 0) return Smi::FromInt(LESS);
7220 else if (d > 0) return Smi::FromInt(GREATER);
7221 }
7222
7223 // x is (non-trivial) prefix of y:
7224 if (bufy.has_more()) return Smi::FromInt(LESS);
7225 // y is prefix of x:
7226 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7227}
7228
7229
7230static Object* FlatStringCompare(String* x, String* y) {
7231 ASSERT(x->IsFlat());
7232 ASSERT(y->IsFlat());
7233 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7234 int prefix_length = x->length();
7235 if (y->length() < prefix_length) {
7236 prefix_length = y->length();
7237 equal_prefix_result = Smi::FromInt(GREATER);
7238 } else if (y->length() > prefix_length) {
7239 equal_prefix_result = Smi::FromInt(LESS);
7240 }
7241 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007242 String::FlatContent x_content = x->GetFlatContent();
7243 String::FlatContent y_content = y->GetFlatContent();
7244 if (x_content.IsAscii()) {
7245 Vector<const char> x_chars = x_content.ToAsciiVector();
7246 if (y_content.IsAscii()) {
7247 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007248 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007249 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007250 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007251 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7252 }
7253 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007254 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7255 if (y_content.IsAscii()) {
7256 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007257 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7258 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007259 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007260 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7261 }
7262 }
7263 Object* result;
7264 if (r == 0) {
7265 result = equal_prefix_result;
7266 } else {
7267 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7268 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007269 ASSERT(result ==
7270 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007271 return result;
7272}
7273
7274
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007275RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007276 NoHandleAllocation ha;
7277 ASSERT(args.length() == 2);
7278
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007279 CONVERT_ARG_CHECKED(String, x, 0);
7280 CONVERT_ARG_CHECKED(String, y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007281
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007282 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007283
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007284 // A few fast case tests before we flatten.
7285 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007286 if (y->length() == 0) {
7287 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007288 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007289 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007290 return Smi::FromInt(LESS);
7291 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007292
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007293 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007294 if (d < 0) return Smi::FromInt(LESS);
7295 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007296
lrn@chromium.org303ada72010-10-27 09:33:13 +00007297 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007298 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007299 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7300 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007301 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007302 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7303 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007304
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007305 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007306 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007307}
7308
7309
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007310RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007311 NoHandleAllocation ha;
7312 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007313 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007314
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007315 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007316 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007317}
7318
7319
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007320RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007321 NoHandleAllocation ha;
7322 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007323 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007324
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007325 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007326 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007327}
7328
7329
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007330RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007331 NoHandleAllocation ha;
7332 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007333 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007334
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007335 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007336 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007337}
7338
7339
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007340static const double kPiDividedBy4 = 0.78539816339744830962;
7341
7342
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007343RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007344 NoHandleAllocation ha;
7345 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007346 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007347
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007348 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7349 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007350 double result;
7351 if (isinf(x) && isinf(y)) {
7352 // Make sure that the result in case of two infinite arguments
7353 // is a multiple of Pi / 4. The sign of the result is determined
7354 // by the first argument (x) and the sign of the second argument
7355 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007356 int multiplier = (x < 0) ? -1 : 1;
7357 if (y < 0) multiplier *= 3;
7358 result = multiplier * kPiDividedBy4;
7359 } else {
7360 result = atan2(x, y);
7361 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007362 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007363}
7364
7365
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007366RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007367 NoHandleAllocation ha;
7368 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007369 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007370
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007371 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007372 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007373}
7374
7375
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007376RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007377 NoHandleAllocation ha;
7378 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007379 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007380
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007381 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007382 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007383}
7384
7385
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007386RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007387 NoHandleAllocation ha;
7388 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007389 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007390
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007391 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007392 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007393}
7394
7395
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007396RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007397 NoHandleAllocation ha;
7398 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007399 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007400
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007401 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007402 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007403}
7404
7405
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007406RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007407 NoHandleAllocation ha;
7408 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007409 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007410
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007411 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007412 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007413}
7414
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007415// Slow version of Math.pow. We check for fast paths for special cases.
7416// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007417RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007418 NoHandleAllocation ha;
7419 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007420 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007421
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007422 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007423
7424 // If the second argument is a smi, it is much faster to call the
7425 // custom powi() function than the generic pow().
7426 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007427 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007428 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007429 }
7430
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007431 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007432 int y_int = static_cast<int>(y);
7433 double result;
7434 if (y == y_int) {
7435 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7436 } else if (y == 0.5) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007437 result = (isinf(x)) ? V8_INFINITY
7438 : fast_sqrt(x + 0.0); // Convert -0 to +0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007439 } else if (y == -0.5) {
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007440 result = (isinf(x)) ? 0
7441 : 1.0 / fast_sqrt(x + 0.0); // Convert -0 to +0.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007442 } else {
7443 result = power_double_double(x, y);
7444 }
7445 if (isnan(result)) return isolate->heap()->nan_value();
7446 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007447}
7448
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007449// 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 +00007450// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007451RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007452 NoHandleAllocation ha;
7453 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007454 isolate->counters()->math_pow()->Increment();
7455
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007456 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7457 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007458 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007459 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007460 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007461 double result = power_double_double(x, y);
7462 if (isnan(result)) return isolate->heap()->nan_value();
7463 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007464 }
7465}
7466
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007467
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007468RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007469 NoHandleAllocation ha;
7470 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007471 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007472
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007473 if (!args[0]->IsHeapNumber()) {
7474 // Must be smi. Return the argument unchanged for all the other types
7475 // to make fuzz-natives test happy.
7476 return args[0];
7477 }
7478
7479 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7480
7481 double value = number->value();
7482 int exponent = number->get_exponent();
7483 int sign = number->get_sign();
7484
danno@chromium.org160a7b02011-04-18 15:51:38 +00007485 if (exponent < -1) {
7486 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7487 if (sign) return isolate->heap()->minus_zero_value();
7488 return Smi::FromInt(0);
7489 }
7490
7491 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7492 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007493 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007494 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007495 return Smi::FromInt(static_cast<int>(value + 0.5));
7496 }
7497
7498 // If the magnitude is big enough, there's no place for fraction part. If we
7499 // try to add 0.5 to this number, 1.0 will be added instead.
7500 if (exponent >= 52) {
7501 return number;
7502 }
7503
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007504 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007505
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007506 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007507 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007508}
7509
7510
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007511RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007512 NoHandleAllocation ha;
7513 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007514 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007515
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007516 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007517 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007518}
7519
7520
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007521RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007522 NoHandleAllocation ha;
7523 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007524 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007525
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007526 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007527 return isolate->heap()->AllocateHeapNumber(fast_sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007528}
7529
7530
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007531RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007532 NoHandleAllocation ha;
7533 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007534 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007535
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007536 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007537 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007538}
7539
7540
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007541RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007542 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007543 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007544
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007545 CONVERT_SMI_ARG_CHECKED(year, 0);
7546 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007547
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007548 return Smi::FromInt(isolate->date_cache()->DaysFromYearMonth(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007549}
7550
7551
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007552RUNTIME_FUNCTION(MaybeObject*, Runtime_DateSetValue) {
7553 HandleScope scope(isolate);
7554 ASSERT(args.length() == 3);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007555
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007556 CONVERT_ARG_HANDLE_CHECKED(JSDate, date, 0);
7557 CONVERT_DOUBLE_ARG_CHECKED(time, 1);
7558 CONVERT_SMI_ARG_CHECKED(is_utc, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007559
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007560 DateCache* date_cache = isolate->date_cache();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007561
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007562 Object* value = NULL;
7563 bool is_value_nan = false;
7564 if (isnan(time)) {
7565 value = isolate->heap()->nan_value();
7566 is_value_nan = true;
7567 } else if (!is_utc &&
7568 (time < -DateCache::kMaxTimeBeforeUTCInMs ||
7569 time > DateCache::kMaxTimeBeforeUTCInMs)) {
7570 value = isolate->heap()->nan_value();
7571 is_value_nan = true;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007572 } else {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007573 time = is_utc ? time : date_cache->ToUTC(static_cast<int64_t>(time));
7574 if (time < -DateCache::kMaxTimeInMs ||
7575 time > DateCache::kMaxTimeInMs) {
7576 value = isolate->heap()->nan_value();
7577 is_value_nan = true;
7578 } else {
7579 MaybeObject* maybe_result =
7580 isolate->heap()->AllocateHeapNumber(DoubleToInteger(time));
7581 if (!maybe_result->ToObject(&value)) return maybe_result;
7582 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007583 }
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00007584 date->SetValue(value, is_value_nan);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00007585 return value;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007586}
7587
7588
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007589RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007590 HandleScope scope(isolate);
7591 ASSERT(args.length() == 3);
7592
7593 Handle<JSFunction> callee = args.at<JSFunction>(0);
7594 Object** parameters = reinterpret_cast<Object**>(args[1]);
7595 const int argument_count = Smi::cast(args[2])->value();
7596
7597 Handle<JSObject> result =
7598 isolate->factory()->NewArgumentsObject(callee, argument_count);
7599 // Allocate the elements if needed.
7600 int parameter_count = callee->shared()->formal_parameter_count();
7601 if (argument_count > 0) {
7602 if (parameter_count > 0) {
7603 int mapped_count = Min(argument_count, parameter_count);
7604 Handle<FixedArray> parameter_map =
7605 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7606 parameter_map->set_map(
7607 isolate->heap()->non_strict_arguments_elements_map());
7608
7609 Handle<Map> old_map(result->map());
7610 Handle<Map> new_map =
7611 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007612 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007613
7614 result->set_map(*new_map);
7615 result->set_elements(*parameter_map);
7616
7617 // Store the context and the arguments array at the beginning of the
7618 // parameter map.
7619 Handle<Context> context(isolate->context());
7620 Handle<FixedArray> arguments =
7621 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7622 parameter_map->set(0, *context);
7623 parameter_map->set(1, *arguments);
7624
7625 // Loop over the actual parameters backwards.
7626 int index = argument_count - 1;
7627 while (index >= mapped_count) {
7628 // These go directly in the arguments array and have no
7629 // corresponding slot in the parameter map.
7630 arguments->set(index, *(parameters - index - 1));
7631 --index;
7632 }
7633
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007634 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007635 while (index >= 0) {
7636 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007637 Handle<String> name(scope_info->ParameterName(index));
7638 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007639 bool duplicate = false;
7640 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007641 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007642 duplicate = true;
7643 break;
7644 }
7645 }
7646
7647 if (duplicate) {
7648 // This goes directly in the arguments array with a hole in the
7649 // parameter map.
7650 arguments->set(index, *(parameters - index - 1));
7651 parameter_map->set_the_hole(index + 2);
7652 } else {
7653 // The context index goes in the parameter map with a hole in the
7654 // arguments array.
7655 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007656 for (int j = 0; j < context_local_count; ++j) {
7657 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007658 context_index = j;
7659 break;
7660 }
7661 }
7662 ASSERT(context_index >= 0);
7663 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007664 parameter_map->set(index + 2, Smi::FromInt(
7665 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007666 }
7667
7668 --index;
7669 }
7670 } else {
7671 // If there is no aliasing, the arguments object elements are not
7672 // special in any way.
7673 Handle<FixedArray> elements =
7674 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7675 result->set_elements(*elements);
7676 for (int i = 0; i < argument_count; ++i) {
7677 elements->set(i, *(parameters - i - 1));
7678 }
7679 }
7680 }
7681 return *result;
7682}
7683
7684
7685RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007686 NoHandleAllocation ha;
7687 ASSERT(args.length() == 3);
7688
7689 JSFunction* callee = JSFunction::cast(args[0]);
7690 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007691 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007692
lrn@chromium.org303ada72010-10-27 09:33:13 +00007693 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007694 { MaybeObject* maybe_result =
7695 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007696 if (!maybe_result->ToObject(&result)) return maybe_result;
7697 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007698 // Allocate the elements if needed.
7699 if (length > 0) {
7700 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007701 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007702 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007703 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7704 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007705
7706 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007707 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007708 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007709 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007710
7711 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007712 for (int i = 0; i < length; i++) {
7713 array->set(i, *--parameters, mode);
7714 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007715 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007716 }
7717 return result;
7718}
7719
7720
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007721RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007722 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007723 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007724 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
7725 CONVERT_ARG_HANDLE_CHECKED(SharedFunctionInfo, shared, 1);
7726 CONVERT_BOOLEAN_ARG_CHECKED(pretenure, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007727
whesse@chromium.org7b260152011-06-20 15:33:18 +00007728 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007729 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007730 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007731 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007732 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7733 context,
7734 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007735 return *result;
7736}
7737
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007738
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007739// Find the arguments of the JavaScript function invocation that called
7740// into C++ code. Collect these in a newly allocated array of handles (possibly
7741// prefixed by a number of empty handles).
7742static SmartArrayPointer<Handle<Object> > GetCallerArguments(
7743 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007744 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007745 // Find frame containing arguments passed to the caller.
7746 JavaScriptFrameIterator it;
7747 JavaScriptFrame* frame = it.frame();
7748 List<JSFunction*> functions(2);
7749 frame->GetFunctions(&functions);
7750 if (functions.length() > 1) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007751 int inlined_jsframe_index = functions.length() - 1;
7752 JSFunction* inlined_function = functions[inlined_jsframe_index];
7753 Vector<SlotRef> args_slots =
7754 SlotRef::ComputeSlotMappingForArguments(
7755 frame,
7756 inlined_jsframe_index,
7757 inlined_function->shared()->formal_parameter_count());
7758
7759 int args_count = args_slots.length();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007760
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007761 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007762 SmartArrayPointer<Handle<Object> > param_data(
7763 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007764 for (int i = 0; i < args_count; i++) {
7765 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007766 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007767 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00007768
7769 args_slots.Dispose();
7770
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007771 return param_data;
7772 } else {
7773 it.AdvanceToArgumentsFrame();
7774 frame = it.frame();
7775 int args_count = frame->ComputeParametersCount();
7776
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007777 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007778 SmartArrayPointer<Handle<Object> > param_data(
7779 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007780 for (int i = 0; i < args_count; i++) {
7781 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007782 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007783 }
7784 return param_data;
7785 }
7786}
7787
7788
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007789RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
7790 HandleScope scope(isolate);
7791 ASSERT(args.length() == 4);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007792 CONVERT_ARG_HANDLE_CHECKED(JSFunction, bound_function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007793 RUNTIME_ASSERT(args[3]->IsNumber());
7794 Handle<Object> bindee = args.at<Object>(1);
7795
7796 // TODO(lrn): Create bound function in C++ code from premade shared info.
7797 bound_function->shared()->set_bound(true);
7798 // Get all arguments of calling function (Function.prototype.bind).
7799 int argc = 0;
7800 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
7801 // Don't count the this-arg.
7802 if (argc > 0) {
7803 ASSERT(*arguments[0] == args[2]);
7804 argc--;
7805 } else {
7806 ASSERT(args[2]->IsUndefined());
7807 }
7808 // Initialize array of bindings (function, this, and any existing arguments
7809 // if the function was already bound).
7810 Handle<FixedArray> new_bindings;
7811 int i;
7812 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
7813 Handle<FixedArray> old_bindings(
7814 JSFunction::cast(*bindee)->function_bindings());
7815 new_bindings =
7816 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
7817 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
7818 i = 0;
7819 for (int n = old_bindings->length(); i < n; i++) {
7820 new_bindings->set(i, old_bindings->get(i));
7821 }
7822 } else {
7823 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
7824 new_bindings = isolate->factory()->NewFixedArray(array_size);
7825 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
7826 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
7827 i = 2;
7828 }
7829 // Copy arguments, skipping the first which is "this_arg".
7830 for (int j = 0; j < argc; j++, i++) {
7831 new_bindings->set(i, *arguments[j + 1]);
7832 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007833 new_bindings->set_map_no_write_barrier(
7834 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007835 bound_function->set_function_bindings(*new_bindings);
7836
7837 // Update length.
7838 Handle<String> length_symbol = isolate->factory()->length_symbol();
7839 Handle<Object> new_length(args.at<Object>(3));
7840 PropertyAttributes attr =
7841 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
7842 ForceSetProperty(bound_function, length_symbol, new_length, attr);
7843 return *bound_function;
7844}
7845
7846
7847RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
7848 HandleScope handles(isolate);
7849 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007850 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007851 if (callable->IsJSFunction()) {
7852 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
7853 if (function->shared()->bound()) {
7854 Handle<FixedArray> bindings(function->function_bindings());
7855 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
7856 return *isolate->factory()->NewJSArrayWithElements(bindings);
7857 }
7858 }
7859 return isolate->heap()->undefined_value();
7860}
7861
7862
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007863RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007864 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007865 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007866 // First argument is a function to use as a constructor.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00007867 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007868 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007869
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007870 // The argument is a bound function. Extract its bound arguments
7871 // and callable.
7872 Handle<FixedArray> bound_args =
7873 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
7874 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
7875 Handle<Object> bound_function(
7876 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
7877 ASSERT(!bound_function->IsJSFunction() ||
7878 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007879
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007880 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007881 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007882 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007883 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007884 param_data[i] = Handle<Object>(bound_args->get(
7885 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007886 }
7887
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007888 if (!bound_function->IsJSFunction()) {
7889 bool exception_thrown;
7890 bound_function = Execution::TryGetConstructorDelegate(bound_function,
7891 &exception_thrown);
7892 if (exception_thrown) return Failure::Exception();
7893 }
7894 ASSERT(bound_function->IsJSFunction());
7895
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007896 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007897 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007898 Execution::New(Handle<JSFunction>::cast(bound_function),
7899 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007900 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007901 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007902 }
7903 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007904 return *result;
7905}
7906
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007907
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007908static void TrySettingInlineConstructStub(Isolate* isolate,
7909 Handle<JSFunction> function) {
7910 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007911 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007912 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007913 }
7914 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007915 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007916 Handle<Code> code = compiler.CompileConstructStub(function);
7917 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007918 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007919}
7920
7921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007922RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007923 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007924 ASSERT(args.length() == 1);
7925
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007926 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007927
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007928 // If the constructor isn't a proper function we throw a type error.
7929 if (!constructor->IsJSFunction()) {
7930 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7931 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007932 isolate->factory()->NewTypeError("not_constructor", arguments);
7933 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007934 }
7935
7936 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007937
7938 // If function should not have prototype, construction is not allowed. In this
7939 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007940 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007941 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7942 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007943 isolate->factory()->NewTypeError("not_constructor", arguments);
7944 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007945 }
7946
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007947#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007948 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007949 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007950 if (debug->StepInActive()) {
7951 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007952 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007953#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007954
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007955 if (function->has_initial_map()) {
7956 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007957 // The 'Function' function ignores the receiver object when
7958 // called using 'new' and creates a new JSFunction object that
7959 // is returned. The receiver object is only used for error
7960 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007961 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007962 // allocate JSFunctions since it does not properly initialize
7963 // the shared part of the function. Since the receiver is
7964 // ignored anyway, we use the global object as the receiver
7965 // instead of a new JSFunction object. This way, errors are
7966 // reported the same way whether or not 'Function' is called
7967 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007968 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007969 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007970 }
7971
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007972 // The function should be compiled for the optimization hints to be
7973 // available. We cannot use EnsureCompiled because that forces a
7974 // compilation through the shared function info which makes it
7975 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007976 if (!function->is_compiled()) {
7977 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
7978 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007979
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007980 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007981 if (!function->has_initial_map() &&
7982 shared->IsInobjectSlackTrackingInProgress()) {
7983 // The tracking is already in progress for another function. We can only
7984 // track one initial_map at a time, so we force the completion before the
7985 // function is called as a constructor for the first time.
7986 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007987 }
7988
7989 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007990 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7991 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007992 // Delay setting the stub if inobject slack tracking is in progress.
7993 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007994 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007995 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007996
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007997 isolate->counters()->constructed_objects()->Increment();
7998 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007999
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008000 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008001}
8002
8003
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008004RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008005 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008006 ASSERT(args.length() == 1);
8007
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008008 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008009 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008010 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008011
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008012 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008013}
8014
8015
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008016RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008017 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008018 ASSERT(args.length() == 1);
8019
8020 Handle<JSFunction> function = args.at<JSFunction>(0);
8021#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008022 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008023 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008024 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008025 PrintF("]\n");
8026 }
8027#endif
8028
lrn@chromium.org34e60782011-09-15 07:25:40 +00008029 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008030 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008031 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008032 return Failure::Exception();
8033 }
8034
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008035 // All done. Return the compiled code.
8036 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008037 return function->code();
8038}
8039
8040
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008041RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008042 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008043 ASSERT(args.length() == 1);
8044 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008045
8046 // If the function is not compiled ignore the lazy
8047 // recompilation. This can happen if the debugger is activated and
8048 // the function is returned to the not compiled state.
8049 if (!function->shared()->is_compiled()) {
8050 function->ReplaceCode(function->shared()->code());
8051 return function->code();
8052 }
8053
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008054 // If the function is not optimizable or debugger is active continue using the
8055 // code from the full compiler.
8056 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008057 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008058 if (FLAG_trace_opt) {
8059 PrintF("[failed to optimize ");
8060 function->PrintName();
8061 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8062 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008063 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008064 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008065 function->ReplaceCode(function->shared()->code());
8066 return function->code();
8067 }
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00008068 function->shared()->code()->set_profiler_ticks(0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008069 if (JSFunction::CompileOptimized(function,
8070 AstNode::kNoNumber,
8071 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008072 return function->code();
8073 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008074 if (FLAG_trace_opt) {
8075 PrintF("[failed to optimize ");
8076 function->PrintName();
8077 PrintF(": optimized compilation failed]\n");
8078 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008079 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008080 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008081}
8082
8083
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008084class ActivationsFinder : public ThreadVisitor {
8085 public:
8086 explicit ActivationsFinder(JSFunction* function)
8087 : function_(function), has_activations_(false) {}
8088
8089 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8090 if (has_activations_) return;
8091
8092 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8093 JavaScriptFrame* frame = it.frame();
8094 if (frame->is_optimized() && frame->function() == function_) {
8095 has_activations_ = true;
8096 return;
8097 }
8098 }
8099 }
8100
8101 bool has_activations() { return has_activations_; }
8102
8103 private:
8104 JSFunction* function_;
8105 bool has_activations_;
8106};
8107
8108
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008109static void MaterializeArgumentsObjectInFrame(Isolate* isolate,
8110 JavaScriptFrame* frame) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008111 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008112 Handle<Object> arguments;
8113 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008114 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008115 if (arguments.is_null()) {
8116 // FunctionGetArguments can't throw an exception, so cast away the
8117 // doubt with an assert.
8118 arguments = Handle<Object>(
8119 Accessors::FunctionGetArguments(*function,
8120 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008121 ASSERT(*arguments != isolate->heap()->null_value());
8122 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008123 }
8124 frame->SetExpression(i, *arguments);
8125 }
8126 }
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008127}
8128
8129
8130RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
8131 HandleScope scope(isolate);
8132 ASSERT(args.length() == 1);
8133 RUNTIME_ASSERT(args[0]->IsSmi());
8134 Deoptimizer::BailoutType type =
8135 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
8136 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8137 ASSERT(isolate->heap()->IsAllocationAllowed());
8138 int jsframes = deoptimizer->jsframe_count();
8139
8140 deoptimizer->MaterializeHeapNumbers();
8141 delete deoptimizer;
8142
8143 JavaScriptFrameIterator it(isolate);
8144 for (int i = 0; i < jsframes - 1; i++) {
8145 MaterializeArgumentsObjectInFrame(isolate, it.frame());
8146 it.Advance();
8147 }
8148
8149 JavaScriptFrame* frame = it.frame();
8150 RUNTIME_ASSERT(frame->function()->IsJSFunction());
8151 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
8152 MaterializeArgumentsObjectInFrame(isolate, frame);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008153
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008154 if (type == Deoptimizer::EAGER) {
8155 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008156 }
8157
8158 // Avoid doing too much work when running with --always-opt and keep
8159 // the optimized code around.
8160 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008161 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008162 }
8163
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008164 // Find other optimized activations of the function.
8165 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008166 while (!it.done()) {
8167 JavaScriptFrame* frame = it.frame();
8168 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008169 has_other_activations = true;
8170 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008171 }
8172 it.Advance();
8173 }
8174
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008175 if (!has_other_activations) {
8176 ActivationsFinder activations_finder(*function);
8177 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8178 has_other_activations = activations_finder.has_activations();
8179 }
8180
8181 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008182 if (FLAG_trace_deopt) {
8183 PrintF("[removing optimized code for: ");
8184 function->PrintName();
8185 PrintF("]\n");
8186 }
8187 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008188 } else {
8189 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008190 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008191 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008192}
8193
8194
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008195RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008196 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008197 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008198 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008199}
8200
8201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008202RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008203 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008204 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008205 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008206 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008207
8208 Deoptimizer::DeoptimizeFunction(*function);
8209
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008210 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008211}
8212
8213
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008214RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8215#if defined(USE_SIMULATOR)
8216 return isolate->heap()->true_value();
8217#else
8218 return isolate->heap()->false_value();
8219#endif
8220}
8221
8222
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008223RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8224 HandleScope scope(isolate);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008225 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008226 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008227
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008228 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8229 function->MarkForLazyRecompilation();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00008230
8231 Code* unoptimized = function->shared()->code();
8232 if (args.length() == 2 &&
8233 unoptimized->kind() == Code::FUNCTION) {
8234 CONVERT_ARG_HANDLE_CHECKED(String, type, 1);
8235 CHECK(type->IsEqualTo(CStrVector("osr")));
8236 isolate->runtime_profiler()->AttemptOnStackReplacement(*function);
8237 unoptimized->set_allow_osr_at_loop_nesting_level(
8238 Code::kMaxLoopNestingMarker);
8239 }
8240
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008241 return isolate->heap()->undefined_value();
8242}
8243
8244
lrn@chromium.org1c092762011-05-09 09:42:16 +00008245RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8246 HandleScope scope(isolate);
8247 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008248 // The least significant bit (after untagging) indicates whether the
8249 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008250 if (!V8::UseCrankshaft()) {
8251 return Smi::FromInt(4); // 4 == "never".
8252 }
8253 if (FLAG_always_opt) {
8254 return Smi::FromInt(3); // 3 == "always".
8255 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008256 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008257 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8258 : Smi::FromInt(2); // 2 == "no".
8259}
8260
8261
8262RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8263 HandleScope scope(isolate);
8264 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008265 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
lrn@chromium.org1c092762011-05-09 09:42:16 +00008266 return Smi::FromInt(function->shared()->opt_count());
8267}
8268
8269
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008270RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008271 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008272 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008273 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008274
8275 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008276 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008277
8278 // We have hit a back edge in an unoptimized frame for a function that was
8279 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008280 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008281 // Keep track of whether we've succeeded in optimizing.
8282 bool succeeded = unoptimized->optimizable();
8283 if (succeeded) {
8284 // If we are trying to do OSR when there are already optimized
8285 // activations of the function, it means (a) the function is directly or
8286 // indirectly recursive and (b) an optimized invocation has been
8287 // deoptimized so that we are currently in an unoptimized activation.
8288 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008289 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008290 while (succeeded && !it.done()) {
8291 JavaScriptFrame* frame = it.frame();
8292 succeeded = !frame->is_optimized() || frame->function() != *function;
8293 it.Advance();
8294 }
8295 }
8296
8297 int ast_id = AstNode::kNoNumber;
8298 if (succeeded) {
8299 // The top JS function is this one, the PC is somewhere in the
8300 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008301 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008302 JavaScriptFrame* frame = it.frame();
8303 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008304 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008305 ASSERT(unoptimized->contains(frame->pc()));
8306
8307 // Use linear search of the unoptimized code's stack check table to find
8308 // the AST id matching the PC.
8309 Address start = unoptimized->instruction_start();
8310 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008311 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008312 uint32_t table_length = Memory::uint32_at(table_cursor);
8313 table_cursor += kIntSize;
8314 for (unsigned i = 0; i < table_length; ++i) {
8315 // Table entries are (AST id, pc offset) pairs.
8316 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8317 if (pc_offset == target_pc_offset) {
8318 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8319 break;
8320 }
8321 table_cursor += 2 * kIntSize;
8322 }
8323 ASSERT(ast_id != AstNode::kNoNumber);
8324 if (FLAG_trace_osr) {
8325 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8326 function->PrintName();
8327 PrintF("]\n");
8328 }
8329
8330 // Try to compile the optimized code. A true return value from
8331 // CompileOptimized means that compilation succeeded, not necessarily
8332 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008333 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008334 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008335 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8336 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008337 if (data->OsrPcOffset()->value() >= 0) {
8338 if (FLAG_trace_osr) {
8339 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008340 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008341 }
8342 ASSERT(data->OsrAstId()->value() == ast_id);
8343 } else {
8344 // We may never generate the desired OSR entry if we emit an
8345 // early deoptimize.
8346 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008347 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008348 } else {
8349 succeeded = false;
8350 }
8351 }
8352
8353 // Revert to the original stack checks in the original unoptimized code.
8354 if (FLAG_trace_osr) {
8355 PrintF("[restoring original stack checks in ");
8356 function->PrintName();
8357 PrintF("]\n");
8358 }
yangguo@chromium.org56454712012-02-16 15:33:53 +00008359 Handle<Code> check_code;
yangguo@chromium.org56454712012-02-16 15:33:53 +00008360 if (FLAG_count_based_interrupts) {
8361 InterruptStub interrupt_stub;
8362 check_code = interrupt_stub.GetCode();
8363 } else // NOLINT
yangguo@chromium.org56454712012-02-16 15:33:53 +00008364 { // NOLINT
8365 StackCheckStub check_stub;
8366 check_code = check_stub.GetCode();
8367 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008368 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008369 Deoptimizer::RevertStackCheckCode(*unoptimized,
8370 *check_code,
8371 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008372
8373 // Allow OSR only at nesting level zero again.
8374 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8375
8376 // If the optimization attempt succeeded, return the AST id tagged as a
8377 // smi. This tells the builtin that we need to translate the unoptimized
8378 // frame to an optimized one.
8379 if (succeeded) {
8380 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8381 return Smi::FromInt(ast_id);
8382 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008383 if (function->IsMarkedForLazyRecompilation()) {
8384 function->ReplaceCode(function->shared()->code());
8385 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008386 return Smi::FromInt(-1);
8387 }
8388}
8389
8390
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008391RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8392 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8393 return isolate->heap()->undefined_value();
8394}
8395
8396
danno@chromium.orgc612e022011-11-10 11:38:15 +00008397RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8398 HandleScope scope(isolate);
8399 ASSERT(args.length() >= 2);
danno@chromium.orgc612e022011-11-10 11:38:15 +00008400 int argc = args.length() - 2;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008401 CONVERT_ARG_CHECKED(JSReceiver, fun, argc + 1);
8402 Object* receiver = args[0];
danno@chromium.orgc612e022011-11-10 11:38:15 +00008403
8404 // If there are too many arguments, allocate argv via malloc.
8405 const int argv_small_size = 10;
8406 Handle<Object> argv_small_buffer[argv_small_size];
8407 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8408 Handle<Object>* argv = argv_small_buffer;
8409 if (argc > argv_small_size) {
8410 argv = new Handle<Object>[argc];
8411 if (argv == NULL) return isolate->StackOverflow();
8412 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8413 }
8414
8415 for (int i = 0; i < argc; ++i) {
8416 MaybeObject* maybe = args[1 + i];
8417 Object* object;
8418 if (!maybe->To<Object>(&object)) return maybe;
8419 argv[i] = Handle<Object>(object);
8420 }
8421
8422 bool threw;
8423 Handle<JSReceiver> hfun(fun);
8424 Handle<Object> hreceiver(receiver);
8425 Handle<Object> result =
8426 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8427
8428 if (threw) return Failure::Exception();
8429 return *result;
8430}
8431
8432
lrn@chromium.org34e60782011-09-15 07:25:40 +00008433RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8434 HandleScope scope(isolate);
8435 ASSERT(args.length() == 5);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008436 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008437 Handle<Object> receiver = args.at<Object>(1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008438 CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008439 CONVERT_SMI_ARG_CHECKED(offset, 3);
8440 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008441 ASSERT(offset >= 0);
8442 ASSERT(argc >= 0);
8443
8444 // If there are too many arguments, allocate argv via malloc.
8445 const int argv_small_size = 10;
8446 Handle<Object> argv_small_buffer[argv_small_size];
8447 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8448 Handle<Object>* argv = argv_small_buffer;
8449 if (argc > argv_small_size) {
8450 argv = new Handle<Object>[argc];
8451 if (argv == NULL) return isolate->StackOverflow();
8452 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8453 }
8454
8455 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008456 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008457 }
8458
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008459 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008460 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008461 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008462
8463 if (threw) return Failure::Exception();
8464 return *result;
8465}
8466
8467
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008468RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008469 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008470 ASSERT(args.length() == 1);
8471 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8472 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8473}
8474
8475
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008476RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008477 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008478 ASSERT(args.length() == 1);
8479 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8480 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8481}
8482
8483
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008484RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008485 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008486 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008487
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008488 CONVERT_ARG_CHECKED(JSFunction, function, 0);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008489 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008490 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008491 { MaybeObject* maybe_result =
8492 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008493 if (!maybe_result->ToObject(&result)) return maybe_result;
8494 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008495
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008496 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008497
kasper.lund7276f142008-07-30 08:49:36 +00008498 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008499}
8500
lrn@chromium.org303ada72010-10-27 09:33:13 +00008501
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008502RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8503 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008504 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008505 JSObject* extension_object;
8506 if (args[0]->IsJSObject()) {
8507 extension_object = JSObject::cast(args[0]);
8508 } else {
8509 // Convert the object to a proper JavaScript object.
8510 MaybeObject* maybe_js_object = args[0]->ToObject();
8511 if (!maybe_js_object->To(&extension_object)) {
8512 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8513 HandleScope scope(isolate);
8514 Handle<Object> handle = args.at<Object>(0);
8515 Handle<Object> result =
8516 isolate->factory()->NewTypeError("with_expression",
8517 HandleVector(&handle, 1));
8518 return isolate->Throw(*result);
8519 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008520 return maybe_js_object;
8521 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008522 }
8523 }
8524
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008525 JSFunction* function;
8526 if (args[1]->IsSmi()) {
8527 // A smi sentinel indicates a context nested inside global code rather
8528 // than some function. There is a canonical empty function that can be
8529 // gotten from the global context.
8530 function = isolate->context()->global_context()->closure();
8531 } else {
8532 function = JSFunction::cast(args[1]);
8533 }
8534
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008535 Context* context;
8536 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008537 isolate->heap()->AllocateWithContext(function,
8538 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008539 extension_object);
8540 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008541 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008542 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008543}
8544
8545
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008546RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008547 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008548 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008549 String* name = String::cast(args[0]);
8550 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008551 JSFunction* function;
8552 if (args[2]->IsSmi()) {
8553 // A smi sentinel indicates a context nested inside global code rather
8554 // than some function. There is a canonical empty function that can be
8555 // gotten from the global context.
8556 function = isolate->context()->global_context()->closure();
8557 } else {
8558 function = JSFunction::cast(args[2]);
8559 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008560 Context* context;
8561 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008562 isolate->heap()->AllocateCatchContext(function,
8563 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008564 name,
8565 thrown_object);
8566 if (!maybe_context->To(&context)) return maybe_context;
8567 isolate->set_context(context);
8568 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008569}
8570
8571
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008572RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8573 NoHandleAllocation ha;
8574 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008575 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008576 JSFunction* function;
8577 if (args[1]->IsSmi()) {
8578 // A smi sentinel indicates a context nested inside global code rather
8579 // than some function. There is a canonical empty function that can be
8580 // gotten from the global context.
8581 function = isolate->context()->global_context()->closure();
8582 } else {
8583 function = JSFunction::cast(args[1]);
8584 }
8585 Context* context;
8586 MaybeObject* maybe_context =
8587 isolate->heap()->AllocateBlockContext(function,
8588 isolate->context(),
8589 scope_info);
8590 if (!maybe_context->To(&context)) return maybe_context;
8591 isolate->set_context(context);
8592 return context;
8593}
8594
8595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008596RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008597 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008598 ASSERT(args.length() == 2);
8599
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008600 CONVERT_ARG_HANDLE_CHECKED(Context, context, 0);
8601 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008602
8603 int index;
8604 PropertyAttributes attributes;
8605 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008606 BindingFlags binding_flags;
8607 Handle<Object> holder = context->Lookup(name,
8608 flags,
8609 &index,
8610 &attributes,
8611 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008612
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008613 // If the slot was not found the result is true.
8614 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008615 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008616 }
8617
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008618 // If the slot was found in a context, it should be DONT_DELETE.
8619 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008620 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008621 }
8622
8623 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008624 // the global object, or the subject of a with. Try to delete it
8625 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008626 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008627 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008628}
8629
8630
ager@chromium.orga1645e22009-09-09 19:27:10 +00008631// A mechanism to return a pair of Object pointers in registers (if possible).
8632// How this is achieved is calling convention-dependent.
8633// All currently supported x86 compiles uses calling conventions that are cdecl
8634// variants where a 64-bit value is returned in two 32-bit registers
8635// (edx:eax on ia32, r1:r0 on ARM).
8636// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8637// In Win64 calling convention, a struct of two pointers is returned in memory,
8638// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008639#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008640struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008641 MaybeObject* x;
8642 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008643};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008644
lrn@chromium.org303ada72010-10-27 09:33:13 +00008645static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008646 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008647 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8648 // In Win64 they are assigned to a hidden first argument.
8649 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008650}
8651#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008652typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008653static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008654 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008655 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008656}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008657#endif
8658
8659
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008660static inline MaybeObject* Unhole(Heap* heap,
8661 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008662 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008663 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8664 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008665 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008666}
8667
8668
danno@chromium.org40cb8782011-05-25 07:58:50 +00008669static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8670 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008671 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008672 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008673 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008674 JSFunction* context_extension_function =
8675 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008676 // If the holder isn't a context extension object, we just return it
8677 // as the receiver. This allows arguments objects to be used as
8678 // receivers, but only if they are put in the context scope chain
8679 // explicitly via a with-statement.
8680 Object* constructor = holder->map()->constructor();
8681 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008682 // Fall back to using the global object as the implicit receiver if
8683 // the property turns out to be a local variable allocated in a
8684 // context extension object - introduced via eval. Implicit global
8685 // receivers are indicated with the hole value.
8686 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008687}
8688
8689
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008690static ObjectPair LoadContextSlotHelper(Arguments args,
8691 Isolate* isolate,
8692 bool throw_error) {
8693 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008694 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008695
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008696 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008697 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008698 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008699 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008700 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008701
8702 int index;
8703 PropertyAttributes attributes;
8704 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008705 BindingFlags binding_flags;
8706 Handle<Object> holder = context->Lookup(name,
8707 flags,
8708 &index,
8709 &attributes,
8710 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008711
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008712 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008713 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008714 ASSERT(holder->IsContext());
8715 // If the "property" we were looking for is a local variable, the
8716 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008717 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008718 // Use the hole as the receiver to signal that the receiver is implicit
8719 // and that the global receiver should be used (as distinguished from an
8720 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00008721 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008722 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008723 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008724 switch (binding_flags) {
8725 case MUTABLE_CHECK_INITIALIZED:
8726 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
8727 if (value->IsTheHole()) {
8728 Handle<Object> reference_error =
8729 isolate->factory()->NewReferenceError("not_defined",
8730 HandleVector(&name, 1));
8731 return MakePair(isolate->Throw(*reference_error), NULL);
8732 }
8733 // FALLTHROUGH
8734 case MUTABLE_IS_INITIALIZED:
8735 case IMMUTABLE_IS_INITIALIZED:
8736 case IMMUTABLE_IS_INITIALIZED_HARMONY:
8737 ASSERT(!value->IsTheHole());
8738 return MakePair(value, *receiver);
8739 case IMMUTABLE_CHECK_INITIALIZED:
8740 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8741 case MISSING_BINDING:
8742 UNREACHABLE();
8743 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008744 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008745 }
8746
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008747 // Otherwise, if the slot was found the holder is a context extension
8748 // object, subject of a with, or a global object. We read the named
8749 // property from it.
8750 if (!holder.is_null()) {
8751 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8752 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008753 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008754 Handle<Object> receiver_handle(object->IsGlobalObject()
8755 ? GlobalObject::cast(*object)->global_receiver()
8756 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008757
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008758 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008759 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008760 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008761 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008762 }
8763
8764 if (throw_error) {
8765 // The property doesn't exist - throw exception.
8766 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008767 isolate->factory()->NewReferenceError("not_defined",
8768 HandleVector(&name, 1));
8769 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008770 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008771 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008772 return MakePair(isolate->heap()->undefined_value(),
8773 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008774 }
8775}
8776
8777
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008778RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008779 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008780}
8781
8782
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008783RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008784 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008785}
8786
8787
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008788RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008789 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008790 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008791
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008792 Handle<Object> value(args[0], isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00008793 CONVERT_ARG_HANDLE_CHECKED(Context, context, 1);
8794 CONVERT_ARG_HANDLE_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00008795 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
8796 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
8797 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008798
8799 int index;
8800 PropertyAttributes attributes;
8801 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008802 BindingFlags binding_flags;
8803 Handle<Object> holder = context->Lookup(name,
8804 flags,
8805 &index,
8806 &attributes,
8807 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008808
8809 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008810 // The property was found in a context slot.
8811 Handle<Context> context = Handle<Context>::cast(holder);
8812 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
8813 context->get(index)->IsTheHole()) {
8814 Handle<Object> error =
8815 isolate->factory()->NewReferenceError("not_defined",
8816 HandleVector(&name, 1));
8817 return isolate->Throw(*error);
8818 }
8819 // Ignore if read_only variable.
8820 if ((attributes & READ_ONLY) == 0) {
8821 // Context is a fixed array and set cannot fail.
8822 context->set(index, *value);
8823 } else if (strict_mode == kStrictMode) {
8824 // Setting read only property in strict mode.
8825 Handle<Object> error =
8826 isolate->factory()->NewTypeError("strict_cannot_assign",
8827 HandleVector(&name, 1));
8828 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008829 }
8830 return *value;
8831 }
8832
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008833 // Slow case: The property is not in a context slot. It is either in a
8834 // context extension object, a property of the subject of a with, or a
8835 // property of the global object.
8836 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008837
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008838 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008839 // The property exists on the holder.
8840 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008841 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008842 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008843 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008844
8845 if (strict_mode == kStrictMode) {
8846 // Throw in strict mode (assignment to undefined variable).
8847 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008848 isolate->factory()->NewReferenceError(
8849 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008850 return isolate->Throw(*error);
8851 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008852 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008853 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008854 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008855 }
8856
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008857 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008858 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008859 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008860 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008861 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008862 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008863 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008864 // Setting read only property in strict mode.
8865 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008866 isolate->factory()->NewTypeError(
8867 "strict_cannot_assign", HandleVector(&name, 1));
8868 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008869 }
8870 return *value;
8871}
8872
8873
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008874RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008875 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008876 ASSERT(args.length() == 1);
8877
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008878 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008879}
8880
8881
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008882RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008883 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008884 ASSERT(args.length() == 1);
8885
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008886 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008887}
8888
8889
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008890RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008891 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008892 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008893}
8894
8895
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008896RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008897 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008898 ASSERT(args.length() == 1);
8899
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008900 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008901 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008902 isolate->factory()->NewReferenceError("not_defined",
8903 HandleVector(&name, 1));
8904 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008905}
8906
8907
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008908RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008909 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008910
8911 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008912 if (isolate->stack_guard()->IsStackOverflow()) {
8913 NoHandleAllocation na;
8914 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008915 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008916
ulan@chromium.org812308e2012-02-29 15:58:45 +00008917 return Execution::HandleStackGuardInterrupt(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008918}
8919
8920
yangguo@chromium.org56454712012-02-16 15:33:53 +00008921RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
8922 ASSERT(args.length() == 0);
ulan@chromium.org812308e2012-02-29 15:58:45 +00008923 return Execution::HandleStackGuardInterrupt(isolate);
yangguo@chromium.org56454712012-02-16 15:33:53 +00008924}
8925
8926
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008927static int StackSize() {
8928 int n = 0;
8929 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8930 return n;
8931}
8932
8933
8934static void PrintTransition(Object* result) {
8935 // indentation
8936 { const int nmax = 80;
8937 int n = StackSize();
8938 if (n <= nmax)
8939 PrintF("%4d:%*s", n, n, "");
8940 else
8941 PrintF("%4d:%*s", n, nmax, "...");
8942 }
8943
8944 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008945 JavaScriptFrame::PrintTop(stdout, true, false);
8946 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008947 } else {
8948 // function result
8949 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008950 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008951 PrintF("\n");
8952 }
8953}
8954
8955
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008956RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008957 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008958 NoHandleAllocation ha;
8959 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008960 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008961}
8962
8963
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008964RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008965 NoHandleAllocation ha;
8966 PrintTransition(args[0]);
8967 return args[0]; // return TOS
8968}
8969
8970
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008971RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008972 NoHandleAllocation ha;
8973 ASSERT(args.length() == 1);
8974
8975#ifdef DEBUG
8976 if (args[0]->IsString()) {
8977 // If we have a string, assume it's a code "marker"
8978 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008979 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008980 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008981 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8982 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008983 } else {
8984 PrintF("DebugPrint: ");
8985 }
8986 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008987 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008988 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008989 HeapObject::cast(args[0])->map()->Print();
8990 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008991#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008992 // ShortPrint is available in release mode. Print is not.
8993 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008994#endif
8995 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008996 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008997
8998 return args[0]; // return TOS
8999}
9000
9001
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009002RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009003 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009004 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009005 isolate->PrintStack();
9006 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009007}
9008
9009
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009010RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009011 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009012 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009013
9014 // According to ECMA-262, section 15.9.1, page 117, the precision of
9015 // the number in a Date object representing a particular instant in
9016 // time is milliseconds. Therefore, we floor the result of getting
9017 // the OS time.
9018 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009019 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009020}
9021
9022
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009023RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009024 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009025 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009026
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009027 CONVERT_ARG_HANDLE_CHECKED(String, str, 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009028 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009029
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009030 CONVERT_ARG_HANDLE_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009031
9032 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009033 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009034 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009035 RUNTIME_ASSERT(output->HasFastElements());
9036
9037 AssertNoAllocation no_allocation;
9038
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009039 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009040 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9041 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009042 String::FlatContent str_content = str->GetFlatContent();
9043 if (str_content.IsAscii()) {
9044 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009045 output_array,
9046 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009047 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009048 ASSERT(str_content.IsTwoByte());
9049 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009050 output_array,
9051 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009052 }
9053
9054 if (result) {
9055 return *output;
9056 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009057 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009058 }
9059}
9060
9061
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009062RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009063 NoHandleAllocation ha;
9064 ASSERT(args.length() == 1);
9065
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009066 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009067 int64_t time = isolate->date_cache()->EquivalentTime(static_cast<int64_t>(x));
9068 const char* zone = OS::LocalTimezone(static_cast<double>(time));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009069 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009070}
9071
9072
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009073RUNTIME_FUNCTION(MaybeObject*, Runtime_DateToUTC) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009074 NoHandleAllocation ha;
9075 ASSERT(args.length() == 1);
9076
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009077 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00009078 int64_t time = isolate->date_cache()->ToUTC(static_cast<int64_t>(x));
9079
9080 return isolate->heap()->NumberFromDouble(static_cast<double>(time));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009081}
9082
9083
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009084RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009085 ASSERT(args.length() == 1);
9086 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009087 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009088 return JSGlobalObject::cast(global)->global_receiver();
9089}
9090
9091
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009092RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009093 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009094 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009095 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009096
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009097 source = Handle<String>(source->TryFlattenGetString());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009098 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009099 Handle<Object> result;
9100 if (source->IsSeqAsciiString()) {
9101 result = JsonParser<true>::Parse(source);
9102 } else {
9103 result = JsonParser<false>::Parse(source);
9104 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009105 if (result.is_null()) {
9106 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009107 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009108 return Failure::Exception();
9109 }
9110 return *result;
9111}
9112
9113
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009114bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9115 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009116 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9117 // Check with callback if set.
9118 AllowCodeGenerationFromStringsCallback callback =
9119 isolate->allow_code_gen_callback();
9120 if (callback == NULL) {
9121 // No callback set and code generation disallowed.
9122 return false;
9123 } else {
9124 // Callback set. Let it decide if code generation is allowed.
9125 VMState state(isolate, EXTERNAL);
9126 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009127 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009128}
9129
9130
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009131RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009132 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009133 ASSERT_EQ(1, args.length());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009134 CONVERT_ARG_HANDLE_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009135
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009136 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009137 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009138
9139 // Check if global context allows code generation from
9140 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009141 if (context->allow_code_gen_from_strings()->IsFalse() &&
9142 !CodeGenerationFromStringsAllowed(isolate, context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009143 return isolate->Throw(*isolate->factory()->NewError(
9144 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9145 }
9146
9147 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009148 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009149 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009150 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009151 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009152 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9153 context,
9154 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009155 return *fun;
9156}
9157
9158
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009159static ObjectPair CompileGlobalEval(Isolate* isolate,
9160 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009161 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009162 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009163 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009164 Handle<Context> context = Handle<Context>(isolate->context());
9165 Handle<Context> global_context = Handle<Context>(context->global_context());
9166
9167 // Check if global context allows code generation from
9168 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009169 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9170 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009171 isolate->Throw(*isolate->factory()->NewError(
9172 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9173 return MakePair(Failure::Exception(), NULL);
9174 }
9175
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009176 // Deal with a normal eval call with a string argument. Compile it
9177 // and return the compiled function bound in the local context.
9178 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9179 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009180 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009181 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009182 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009183 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009184 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009185 Handle<JSFunction> compiled =
9186 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009187 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009188 return MakePair(*compiled, *receiver);
9189}
9190
9191
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009192RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009193 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009194
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009195 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009196 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009197
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009198 // If "eval" didn't refer to the original GlobalEval, it's not a
9199 // direct call to eval.
9200 // (And even if it is, but the first argument isn't a string, just let
9201 // execution default to an indirect call to eval, which will also return
9202 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009203 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009204 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009205 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009206 }
9207
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009208 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009209 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009210 return CompileGlobalEval(isolate,
9211 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009212 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009213 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009214 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009215}
9216
9217
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009218RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009219 // This utility adjusts the property attributes for newly created Function
9220 // object ("new Function(...)") by changing the map.
9221 // All it does is changing the prototype property to enumerable
9222 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009223 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009224 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009225 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009226
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009227 Handle<Map> map = func->shared()->is_classic_mode()
9228 ? isolate->function_instance_map()
9229 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009230
9231 ASSERT(func->map()->instance_type() == map->instance_type());
9232 ASSERT(func->map()->instance_size() == map->instance_size());
9233 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009234 return *func;
9235}
9236
9237
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009238RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009239 // Allocate a block of memory in NewSpace (filled with a filler).
9240 // Use as fallback for allocation in generated code when NewSpace
9241 // is full.
9242 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009243 CONVERT_ARG_HANDLE_CHECKED(Smi, size_smi, 0);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009244 int size = size_smi->value();
9245 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9246 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009247 Heap* heap = isolate->heap();
9248 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009249 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009250 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009251 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009252 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009253 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009254 }
9255 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009256 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009257}
9258
9259
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009260// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009261// array. Returns true if the element was pushed on the stack and
9262// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009263RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009264 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009265 CONVERT_ARG_CHECKED(JSArray, array, 0);
9266 CONVERT_ARG_CHECKED(JSObject, element, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009267 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009268 int length = Smi::cast(array->length())->value();
9269 FixedArray* elements = FixedArray::cast(array->elements());
9270 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009271 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009272 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009273 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009274 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009275 { MaybeObject* maybe_obj =
9276 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009277 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9278 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009279 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009280}
9281
9282
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009283/**
9284 * A simple visitor visits every element of Array's.
9285 * The backend storage can be a fixed array for fast elements case,
9286 * or a dictionary for sparse array. Since Dictionary is a subtype
9287 * of FixedArray, the class can be used by both fast and slow cases.
9288 * The second parameter of the constructor, fast_elements, specifies
9289 * whether the storage is a FixedArray or Dictionary.
9290 *
9291 * An index limit is used to deal with the situation that a result array
9292 * length overflows 32-bit non-negative integer.
9293 */
9294class ArrayConcatVisitor {
9295 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009296 ArrayConcatVisitor(Isolate* isolate,
9297 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009298 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009299 isolate_(isolate),
9300 storage_(Handle<FixedArray>::cast(
9301 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009302 index_offset_(0u),
9303 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009304
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009305 ~ArrayConcatVisitor() {
9306 clear_storage();
9307 }
9308
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009309 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009310 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009311 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009312
9313 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009314 if (index < static_cast<uint32_t>(storage_->length())) {
9315 storage_->set(index, *elm);
9316 return;
9317 }
9318 // Our initial estimate of length was foiled, possibly by
9319 // getters on the arrays increasing the length of later arrays
9320 // during iteration.
9321 // This shouldn't happen in anything but pathological cases.
9322 SetDictionaryMode(index);
9323 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009324 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009325 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009326 Handle<SeededNumberDictionary> dict(
9327 SeededNumberDictionary::cast(*storage_));
9328 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009329 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009330 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009331 // Dictionary needed to grow.
9332 clear_storage();
9333 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009334 }
9335}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009336
9337 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009338 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9339 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009340 } else {
9341 index_offset_ += delta;
9342 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009343 }
9344
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009345 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009346 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009347 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009348 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009349 Handle<Map> map;
9350 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009351 map = isolate_->factory()->GetElementsTransitionMap(array,
9352 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009353 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009354 map = isolate_->factory()->GetElementsTransitionMap(array,
9355 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009356 }
9357 array->set_map(*map);
9358 array->set_length(*length);
9359 array->set_elements(*storage_);
9360 return array;
9361 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009362
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009363 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009364 // Convert storage to dictionary mode.
9365 void SetDictionaryMode(uint32_t index) {
9366 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009367 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009368 Handle<SeededNumberDictionary> slow_storage(
9369 isolate_->factory()->NewSeededNumberDictionary(
9370 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009371 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9372 for (uint32_t i = 0; i < current_length; i++) {
9373 HandleScope loop_scope;
9374 Handle<Object> element(current_storage->get(i));
9375 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009376 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009377 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009378 if (!new_storage.is_identical_to(slow_storage)) {
9379 slow_storage = loop_scope.CloseAndEscape(new_storage);
9380 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009381 }
9382 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009383 clear_storage();
9384 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009385 fast_elements_ = false;
9386 }
9387
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009388 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009389 isolate_->global_handles()->Destroy(
9390 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009391 }
9392
9393 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009394 storage_ = Handle<FixedArray>::cast(
9395 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009396 }
9397
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009398 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009399 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009400 // Index after last seen index. Always less than or equal to
9401 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009402 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009403 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009404};
9405
9406
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009407static uint32_t EstimateElementCount(Handle<JSArray> array) {
9408 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9409 int element_count = 0;
9410 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009411 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009412 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009413 // Fast elements can't have lengths that are not representable by
9414 // a 32-bit signed integer.
9415 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9416 int fast_length = static_cast<int>(length);
9417 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9418 for (int i = 0; i < fast_length; i++) {
9419 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009420 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009421 break;
9422 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009423 case FAST_DOUBLE_ELEMENTS:
9424 // TODO(1810): Decide if it's worthwhile to implement this.
9425 UNREACHABLE();
9426 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009427 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009428 Handle<SeededNumberDictionary> dictionary(
9429 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009430 int capacity = dictionary->Capacity();
9431 for (int i = 0; i < capacity; i++) {
9432 Handle<Object> key(dictionary->KeyAt(i));
9433 if (dictionary->IsKey(*key)) {
9434 element_count++;
9435 }
9436 }
9437 break;
9438 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009439 case NON_STRICT_ARGUMENTS_ELEMENTS:
9440 case EXTERNAL_BYTE_ELEMENTS:
9441 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9442 case EXTERNAL_SHORT_ELEMENTS:
9443 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9444 case EXTERNAL_INT_ELEMENTS:
9445 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9446 case EXTERNAL_FLOAT_ELEMENTS:
9447 case EXTERNAL_DOUBLE_ELEMENTS:
9448 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009449 // External arrays are always dense.
9450 return length;
9451 }
9452 // As an estimate, we assume that the prototype doesn't contain any
9453 // inherited elements.
9454 return element_count;
9455}
9456
9457
9458
9459template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009460static void IterateExternalArrayElements(Isolate* isolate,
9461 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009462 bool elements_are_ints,
9463 bool elements_are_guaranteed_smis,
9464 ArrayConcatVisitor* visitor) {
9465 Handle<ExternalArrayClass> array(
9466 ExternalArrayClass::cast(receiver->elements()));
9467 uint32_t len = static_cast<uint32_t>(array->length());
9468
9469 ASSERT(visitor != NULL);
9470 if (elements_are_ints) {
9471 if (elements_are_guaranteed_smis) {
9472 for (uint32_t j = 0; j < len; j++) {
9473 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009474 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009475 visitor->visit(j, e);
9476 }
9477 } else {
9478 for (uint32_t j = 0; j < len; j++) {
9479 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009480 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009481 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9482 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9483 visitor->visit(j, e);
9484 } else {
9485 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009486 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009487 visitor->visit(j, e);
9488 }
9489 }
9490 }
9491 } else {
9492 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009493 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009494 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009495 visitor->visit(j, e);
9496 }
9497 }
9498}
9499
9500
9501// Used for sorting indices in a List<uint32_t>.
9502static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9503 uint32_t a = *ap;
9504 uint32_t b = *bp;
9505 return (a == b) ? 0 : (a < b) ? -1 : 1;
9506}
9507
9508
9509static void CollectElementIndices(Handle<JSObject> object,
9510 uint32_t range,
9511 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009512 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009513 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009514 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009515 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009516 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9517 uint32_t length = static_cast<uint32_t>(elements->length());
9518 if (range < length) length = range;
9519 for (uint32_t i = 0; i < length; i++) {
9520 if (!elements->get(i)->IsTheHole()) {
9521 indices->Add(i);
9522 }
9523 }
9524 break;
9525 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009526 case FAST_DOUBLE_ELEMENTS: {
9527 // TODO(1810): Decide if it's worthwhile to implement this.
9528 UNREACHABLE();
9529 break;
9530 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009531 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009532 Handle<SeededNumberDictionary> dict(
9533 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009534 uint32_t capacity = dict->Capacity();
9535 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009536 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009537 Handle<Object> k(dict->KeyAt(j));
9538 if (dict->IsKey(*k)) {
9539 ASSERT(k->IsNumber());
9540 uint32_t index = static_cast<uint32_t>(k->Number());
9541 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009542 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009543 }
9544 }
9545 }
9546 break;
9547 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009548 default: {
9549 int dense_elements_length;
9550 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009551 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009552 dense_elements_length =
9553 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009554 break;
9555 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009556 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009557 dense_elements_length =
9558 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009559 break;
9560 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009561 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009562 dense_elements_length =
9563 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009564 break;
9565 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009566 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009567 dense_elements_length =
9568 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009569 break;
9570 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009571 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009572 dense_elements_length =
9573 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009574 break;
9575 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009576 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009577 dense_elements_length =
9578 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009579 break;
9580 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009581 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009582 dense_elements_length =
9583 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009584 break;
9585 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009586 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009587 dense_elements_length =
9588 ExternalFloatArray::cast(object->elements())->length();
9589 break;
9590 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009591 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009592 dense_elements_length =
9593 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009594 break;
9595 }
9596 default:
9597 UNREACHABLE();
9598 dense_elements_length = 0;
9599 break;
9600 }
9601 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9602 if (range <= length) {
9603 length = range;
9604 // We will add all indices, so we might as well clear it first
9605 // and avoid duplicates.
9606 indices->Clear();
9607 }
9608 for (uint32_t i = 0; i < length; i++) {
9609 indices->Add(i);
9610 }
9611 if (length == range) return; // All indices accounted for already.
9612 break;
9613 }
9614 }
9615
9616 Handle<Object> prototype(object->GetPrototype());
9617 if (prototype->IsJSObject()) {
9618 // The prototype will usually have no inherited element indices,
9619 // but we have to check.
9620 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9621 }
9622}
9623
9624
9625/**
9626 * A helper function that visits elements of a JSArray in numerical
9627 * order.
9628 *
9629 * The visitor argument called for each existing element in the array
9630 * with the element index and the element's value.
9631 * Afterwards it increments the base-index of the visitor by the array
9632 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009633 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009634 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009635static bool IterateElements(Isolate* isolate,
9636 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009637 ArrayConcatVisitor* visitor) {
9638 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9639 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009640 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009641 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009642 // Run through the elements FixedArray and use HasElement and GetElement
9643 // to check the prototype for missing elements.
9644 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9645 int fast_length = static_cast<int>(length);
9646 ASSERT(fast_length <= elements->length());
9647 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009648 HandleScope loop_scope(isolate);
9649 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009650 if (!element_value->IsTheHole()) {
9651 visitor->visit(j, element_value);
9652 } else if (receiver->HasElement(j)) {
9653 // Call GetElement on receiver, not its prototype, or getters won't
9654 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009655 element_value = Object::GetElement(receiver, j);
9656 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009657 visitor->visit(j, element_value);
9658 }
9659 }
9660 break;
9661 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009662 case FAST_DOUBLE_ELEMENTS: {
9663 // TODO(1810): Decide if it's worthwhile to implement this.
9664 UNREACHABLE();
9665 break;
9666 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009667 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009668 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009669 List<uint32_t> indices(dict->Capacity() / 2);
9670 // Collect all indices in the object and the prototypes less
9671 // than length. This might introduce duplicates in the indices list.
9672 CollectElementIndices(receiver, length, &indices);
9673 indices.Sort(&compareUInt32);
9674 int j = 0;
9675 int n = indices.length();
9676 while (j < n) {
9677 HandleScope loop_scope;
9678 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009679 Handle<Object> element = Object::GetElement(receiver, index);
9680 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009681 visitor->visit(index, element);
9682 // Skip to next different index (i.e., omit duplicates).
9683 do {
9684 j++;
9685 } while (j < n && indices[j] == index);
9686 }
9687 break;
9688 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009689 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009690 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9691 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009692 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009693 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009694 visitor->visit(j, e);
9695 }
9696 break;
9697 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009698 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009699 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009700 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009701 break;
9702 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009703 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009704 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009705 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009706 break;
9707 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009708 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009709 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009710 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009711 break;
9712 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009713 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009714 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009715 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009716 break;
9717 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009718 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009719 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009720 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009721 break;
9722 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009723 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009724 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009725 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009726 break;
9727 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009728 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009729 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009730 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009731 break;
9732 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009733 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009734 IterateExternalArrayElements<ExternalDoubleArray, double>(
9735 isolate, receiver, false, false, visitor);
9736 break;
9737 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009738 default:
9739 UNREACHABLE();
9740 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009741 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009742 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009743 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009744}
9745
9746
9747/**
9748 * Array::concat implementation.
9749 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009750 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009751 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009752 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009753RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009754 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009755 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009756
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009757 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009758 int argument_count = static_cast<int>(arguments->length()->Number());
9759 RUNTIME_ASSERT(arguments->HasFastElements());
9760 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009761
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009762 // Pass 1: estimate the length and number of elements of the result.
9763 // The actual length can be larger if any of the arguments have getters
9764 // that mutate other arguments (but will otherwise be precise).
9765 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009766
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009767 uint32_t estimate_result_length = 0;
9768 uint32_t estimate_nof_elements = 0;
9769 {
9770 for (int i = 0; i < argument_count; i++) {
9771 HandleScope loop_scope;
9772 Handle<Object> obj(elements->get(i));
9773 uint32_t length_estimate;
9774 uint32_t element_estimate;
9775 if (obj->IsJSArray()) {
9776 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009777 // TODO(1810): Find out if it's worthwhile to properly support
9778 // arbitrary ElementsKinds. For now, pessimistically transition to
9779 // FAST_ELEMENTS.
9780 if (array->HasFastDoubleElements()) {
9781 array = Handle<JSArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009782 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009783 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009784 length_estimate =
9785 static_cast<uint32_t>(array->length()->Number());
9786 element_estimate =
9787 EstimateElementCount(array);
9788 } else {
9789 length_estimate = 1;
9790 element_estimate = 1;
9791 }
9792 // Avoid overflows by capping at kMaxElementCount.
9793 if (JSObject::kMaxElementCount - estimate_result_length <
9794 length_estimate) {
9795 estimate_result_length = JSObject::kMaxElementCount;
9796 } else {
9797 estimate_result_length += length_estimate;
9798 }
9799 if (JSObject::kMaxElementCount - estimate_nof_elements <
9800 element_estimate) {
9801 estimate_nof_elements = JSObject::kMaxElementCount;
9802 } else {
9803 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009804 }
9805 }
9806 }
9807
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009808 // If estimated number of elements is more than half of length, a
9809 // fixed array (fast case) is more time and space-efficient than a
9810 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009811 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009812
9813 Handle<FixedArray> storage;
9814 if (fast_case) {
9815 // The backing storage array must have non-existing elements to
9816 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009817 storage = isolate->factory()->NewFixedArrayWithHoles(
9818 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009819 } else {
9820 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9821 uint32_t at_least_space_for = estimate_nof_elements +
9822 (estimate_nof_elements >> 2);
9823 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009824 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009825 }
9826
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009827 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009828
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009829 for (int i = 0; i < argument_count; i++) {
9830 Handle<Object> obj(elements->get(i));
9831 if (obj->IsJSArray()) {
9832 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009833 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009834 return Failure::Exception();
9835 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009836 } else {
9837 visitor.visit(0, obj);
9838 visitor.increase_index_offset(1);
9839 }
9840 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009841
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009842 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009843}
9844
9845
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009846// This will not allocate (flatten the string), but it may run
9847// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009848RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009849 NoHandleAllocation ha;
9850 ASSERT(args.length() == 1);
9851
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009852 CONVERT_ARG_CHECKED(String, string, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009853 StringInputBuffer buffer(string);
9854 while (buffer.has_more()) {
9855 uint16_t character = buffer.GetNext();
9856 PrintF("%c", character);
9857 }
9858 return string;
9859}
9860
ager@chromium.org5ec48922009-05-05 07:25:34 +00009861// Moves all own elements of an object, that are below a limit, to positions
9862// starting at zero. All undefined values are placed after non-undefined values,
9863// and are followed by non-existing element. Does not change the length
9864// property.
9865// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009866RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009867 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009868 CONVERT_ARG_CHECKED(JSObject, object, 0);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009869 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9870 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009871}
9872
9873
9874// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009875RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009876 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009877 CONVERT_ARG_CHECKED(JSArray, from, 0);
9878 CONVERT_ARG_CHECKED(JSArray, to, 1);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009879 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009880 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009881 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009882 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9883 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009884 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009885 } else if (new_elements->map() ==
9886 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009887 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009888 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009889 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009890 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00009891 maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009892 Object* new_map;
9893 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009894 to->set_map(Map::cast(new_map));
9895 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009896 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009897 Object* obj;
9898 { MaybeObject* maybe_obj = from->ResetElements();
9899 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9900 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009901 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009902 return to;
9903}
9904
9905
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009906// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009907RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009908 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009909 CONVERT_ARG_CHECKED(JSObject, object, 0);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009910 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009911 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009912 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
9913 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009914 } else if (object->IsJSArray()) {
9915 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009916 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009917 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009918 }
9919}
9920
9921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009922RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009923 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009924
9925 ASSERT_EQ(3, args.length());
9926
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009927 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009928 Handle<Object> key1 = args.at<Object>(1);
9929 Handle<Object> key2 = args.at<Object>(2);
9930
9931 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009932 if (!key1->ToArrayIndex(&index1)
9933 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009934 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009935 }
9936
ager@chromium.orgac091b72010-05-05 07:34:42 +00009937 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009938 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009939 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009940 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009941 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009942
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009943 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009944 isolate, JSObject::SetElement(jsobject, index1, tmp2, NONE, kStrictMode));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009945 RETURN_IF_EMPTY_HANDLE(
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00009946 isolate, JSObject::SetElement(jsobject, index2, tmp1, NONE, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009947
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009948 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009949}
9950
9951
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009952// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009953// might have elements. Can either return keys (positive integers) or
9954// intervals (pair of a negative integer (-start-1) followed by a
9955// positive (length)) or undefined values.
9956// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009957RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009958 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009959 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +00009960 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009961 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009962 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009963 // Create an array and get all the keys into it, then remove all the
9964 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009965 bool threw = false;
9966 Handle<FixedArray> keys =
9967 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
9968 if (threw) return Failure::Exception();
9969
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009970 int keys_length = keys->length();
9971 for (int i = 0; i < keys_length; i++) {
9972 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009973 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009974 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009975 // Zap invalid keys.
9976 keys->set_undefined(i);
9977 }
9978 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009979 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009980 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009981 ASSERT(array->HasFastElements() ||
9982 array->HasFastSmiOnlyElements() ||
9983 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009984 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009985 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009986 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009987 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009988 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009989 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009990 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009991 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009992 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009993 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009994 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009995 }
9996}
9997
9998
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009999RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010000 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010001 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10002 CONVERT_ARG_CHECKED(String, name, 1);
10003 CONVERT_SMI_ARG_CHECKED(flag, 2);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +000010004 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
10005 return obj->LookupAccessor(name, component);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010006}
10007
10008
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010009#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010010RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010011 ASSERT(args.length() == 0);
10012 return Execution::DebugBreakHelper();
10013}
10014
10015
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010016// Helper functions for wrapping and unwrapping stack frame ids.
10017static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010018 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010019 return Smi::FromInt(id >> 2);
10020}
10021
10022
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010023static StackFrame::Id UnwrapFrameId(int wrapped) {
10024 return static_cast<StackFrame::Id>(wrapped << 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010025}
10026
10027
10028// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010029// args[0]: debug event listener function to set or null or undefined for
10030// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010031// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010032RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010033 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010034 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10035 args[0]->IsUndefined() ||
10036 args[0]->IsNull());
10037 Handle<Object> callback = args.at<Object>(0);
10038 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010039 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010040
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010041 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010042}
10043
10044
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010045RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010046 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010047 isolate->stack_guard()->DebugBreak();
10048 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010049}
10050
10051
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010052static MaybeObject* DebugLookupResultValue(Heap* heap,
10053 Object* receiver,
10054 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010055 LookupResult* result,
10056 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010057 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010058 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010059 case NORMAL:
10060 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010061 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010062 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010063 }
10064 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010065 case FIELD:
10066 value =
10067 JSObject::cast(
10068 result->holder())->FastPropertyAt(result->GetFieldIndex());
10069 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010070 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010071 }
10072 return value;
10073 case CONSTANT_FUNCTION:
10074 return result->GetConstantFunction();
10075 case CALLBACKS: {
10076 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010077 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010078 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10079 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010080 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010081 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010082 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010083 maybe_value = heap->isolate()->pending_exception();
10084 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010085 if (caught_exception != NULL) {
10086 *caught_exception = true;
10087 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010088 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010089 }
10090 return value;
10091 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010092 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010093 }
10094 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010095 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010096 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010097 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010098 case CONSTANT_TRANSITION:
10099 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010100 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010101 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010102 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010103 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010104 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010105 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010106 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010107}
10108
10109
ager@chromium.org32912102009-01-16 10:38:43 +000010110// Get debugger related details for an object property.
10111// args[0]: object holding property
10112// args[1]: name of the property
10113//
10114// The array returned contains the following information:
10115// 0: Property value
10116// 1: Property details
10117// 2: Property value is exception
10118// 3: Getter function if defined
10119// 4: Setter function if defined
10120// Items 2-4 are only filled if the property has either a getter or a setter
10121// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010122RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010123 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010124
10125 ASSERT(args.length() == 2);
10126
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010127 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10128 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010129
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010130 // Make sure to set the current context to the context before the debugger was
10131 // entered (if the debugger is entered). The reason for switching context here
10132 // is that for some property lookups (accessors and interceptors) callbacks
10133 // into the embedding application can occour, and the embedding application
10134 // could have the assumption that its own global context is the current
10135 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010136 SaveContext save(isolate);
10137 if (isolate->debug()->InDebugger()) {
10138 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010139 }
10140
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010141 // Skip the global proxy as it has no properties and always delegates to the
10142 // real global object.
10143 if (obj->IsJSGlobalProxy()) {
10144 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10145 }
10146
10147
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010148 // Check if the name is trivially convertible to an index and get the element
10149 // if so.
10150 uint32_t index;
10151 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010152 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010153 Object* element_or_char;
10154 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010155 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010156 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10157 return maybe_element_or_char;
10158 }
10159 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010160 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010161 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010162 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010163 }
10164
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010165 // Find the number of objects making up this.
10166 int length = LocalPrototypeChainLength(*obj);
10167
10168 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010169 Handle<JSObject> jsproto = obj;
10170 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010171 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010172 jsproto->LocalLookup(*name, &result);
10173 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010174 // LookupResult is not GC safe as it holds raw object pointers.
10175 // GC can happen later in this code so put the required fields into
10176 // local variables using handles when required for later use.
10177 PropertyType result_type = result.type();
10178 Handle<Object> result_callback_obj;
10179 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010180 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10181 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010182 }
10183 Smi* property_details = result.GetPropertyDetails().AsSmi();
10184 // DebugLookupResultValue can cause GC so details from LookupResult needs
10185 // to be copied to handles before this.
10186 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010187 Object* raw_value;
10188 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010189 DebugLookupResultValue(isolate->heap(), *obj, *name,
10190 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010191 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10192 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010193 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010194
10195 // If the callback object is a fixed array then it contains JavaScript
10196 // getter and/or setter.
10197 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010198 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010199 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010200 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010201 details->set(0, *value);
10202 details->set(1, property_details);
10203 if (hasJavaScriptAccessors) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010204 AccessorPair* accessors = AccessorPair::cast(*result_callback_obj);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010205 details->set(2, isolate->heap()->ToBoolean(caught_exception));
danno@chromium.org88aa0582012-03-23 15:11:57 +000010206 details->set(3, accessors->GetComponent(ACCESSOR_GETTER));
10207 details->set(4, accessors->GetComponent(ACCESSOR_SETTER));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010208 }
10209
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010210 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010211 }
10212 if (i < length - 1) {
10213 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10214 }
10215 }
10216
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010217 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010218}
10219
10220
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010221RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010222 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010223
10224 ASSERT(args.length() == 2);
10225
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010226 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
10227 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010228
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010229 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010230 obj->Lookup(*name, &result);
10231 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010232 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010233 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010234 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010235}
10236
10237
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010238// Return the property type calculated from the property details.
10239// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010240RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010241 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010242 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10243 return Smi::FromInt(static_cast<int>(details.type()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010244}
10245
10246
10247// Return the property attribute calculated from the property details.
10248// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010249RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010250 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010251 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10252 return Smi::FromInt(static_cast<int>(details.attributes()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010253}
10254
10255
10256// Return the property insertion index calculated from the property details.
10257// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010258RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010259 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010260 CONVERT_PROPERTY_DETAILS_CHECKED(details, 0);
10261 return Smi::FromInt(details.index());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010262}
10263
10264
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010265// Return property value from named interceptor.
10266// args[0]: object
10267// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010268RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010269 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010270 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010271 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010272 RUNTIME_ASSERT(obj->HasNamedInterceptor());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010273 CONVERT_ARG_HANDLE_CHECKED(String, name, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010274
10275 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010276 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010277}
10278
10279
10280// Return element value from indexed interceptor.
10281// args[0]: object
10282// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010283RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010284 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010285 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010286 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010287 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10288 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10289
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010290 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010291}
10292
10293
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010294RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010295 ASSERT(args.length() >= 1);
10296 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010297 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010298 if (isolate->debug()->break_id() == 0 ||
10299 break_id != isolate->debug()->break_id()) {
10300 return isolate->Throw(
10301 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010302 }
10303
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010304 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010305}
10306
10307
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010308RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010309 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010310 ASSERT(args.length() == 1);
10311
10312 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010313 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010314 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10315 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010316 if (!maybe_result->ToObject(&result)) return maybe_result;
10317 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010318
10319 // Count all frames which are relevant to debugging stack trace.
10320 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010321 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010322 if (id == StackFrame::NO_ID) {
10323 // If there is no JavaScript stack frame count is 0.
10324 return Smi::FromInt(0);
10325 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010326
10327 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10328 n += it.frame()->GetInlineCount();
10329 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010330 return Smi::FromInt(n);
10331}
10332
10333
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010334class FrameInspector {
10335 public:
10336 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010337 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010338 Isolate* isolate)
10339 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10340 // Calculate the deoptimized frame.
10341 if (frame->is_optimized()) {
10342 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010343 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010344 }
10345 has_adapted_arguments_ = frame_->has_adapted_arguments();
ulan@chromium.org967e2702012-02-28 09:49:15 +000010346 is_bottommost_ = inlined_jsframe_index == 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010347 is_optimized_ = frame_->is_optimized();
10348 }
10349
10350 ~FrameInspector() {
10351 // Get rid of the calculated deoptimized frame if any.
10352 if (deoptimized_frame_ != NULL) {
10353 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10354 isolate_);
10355 }
10356 }
10357
10358 int GetParametersCount() {
10359 return is_optimized_
10360 ? deoptimized_frame_->parameters_count()
10361 : frame_->ComputeParametersCount();
10362 }
10363 int expression_count() { return deoptimized_frame_->expression_count(); }
10364 Object* GetFunction() {
10365 return is_optimized_
10366 ? deoptimized_frame_->GetFunction()
10367 : frame_->function();
10368 }
10369 Object* GetParameter(int index) {
10370 return is_optimized_
10371 ? deoptimized_frame_->GetParameter(index)
10372 : frame_->GetParameter(index);
10373 }
10374 Object* GetExpression(int index) {
10375 return is_optimized_
10376 ? deoptimized_frame_->GetExpression(index)
10377 : frame_->GetExpression(index);
10378 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010379 int GetSourcePosition() {
10380 return is_optimized_
10381 ? deoptimized_frame_->GetSourcePosition()
10382 : frame_->LookupCode()->SourcePosition(frame_->pc());
10383 }
ulan@chromium.org967e2702012-02-28 09:49:15 +000010384 bool IsConstructor() {
10385 return is_optimized_ && !is_bottommost_
10386 ? deoptimized_frame_->HasConstructStub()
10387 : frame_->IsConstructor();
10388 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010389
10390 // To inspect all the provided arguments the frame might need to be
10391 // replaced with the arguments frame.
10392 void SetArgumentsFrame(JavaScriptFrame* frame) {
10393 ASSERT(has_adapted_arguments_);
10394 frame_ = frame;
10395 is_optimized_ = frame_->is_optimized();
10396 ASSERT(!is_optimized_);
10397 }
10398
10399 private:
10400 JavaScriptFrame* frame_;
10401 DeoptimizedFrameInfo* deoptimized_frame_;
10402 Isolate* isolate_;
10403 bool is_optimized_;
ulan@chromium.org967e2702012-02-28 09:49:15 +000010404 bool is_bottommost_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010405 bool has_adapted_arguments_;
10406
10407 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10408};
10409
10410
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010411static const int kFrameDetailsFrameIdIndex = 0;
10412static const int kFrameDetailsReceiverIndex = 1;
10413static const int kFrameDetailsFunctionIndex = 2;
10414static const int kFrameDetailsArgumentCountIndex = 3;
10415static const int kFrameDetailsLocalCountIndex = 4;
10416static const int kFrameDetailsSourcePositionIndex = 5;
10417static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010418static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010419static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010420static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010421
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010422
10423static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10424 JavaScriptFrame* frame) {
10425 SaveContext* save = isolate->save_context();
10426 while (save != NULL && !save->IsBelowFrame(frame)) {
10427 save = save->prev();
10428 }
10429 ASSERT(save != NULL);
10430 return save;
10431}
10432
10433
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010434// Return an array with frame details
10435// args[0]: number: break id
10436// args[1]: number: frame index
10437//
10438// The array returned contains the following information:
10439// 0: Frame id
10440// 1: Receiver
10441// 2: Function
10442// 3: Argument count
10443// 4: Local count
10444// 5: Source position
10445// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010446// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010447// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010448// Arguments name, value
10449// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010450// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010451RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010452 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010453 ASSERT(args.length() == 2);
10454
10455 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010456 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010457 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10458 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010459 if (!maybe_check->ToObject(&check)) return maybe_check;
10460 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010461 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010462 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010463
10464 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010465 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010466 if (id == StackFrame::NO_ID) {
10467 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010468 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010469 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010470
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010471 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010472 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010473 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010474 if (index < count + it.frame()->GetInlineCount()) break;
10475 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010476 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010477 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010478
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010479 bool is_optimized = it.frame()->is_optimized();
10480
10481 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10482 if (is_optimized) {
10483 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010484 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010485 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010486 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010487
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010488 // Traverse the saved contexts chain to find the active context for the
10489 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010490 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010491
10492 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010493 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010494
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010495 // Find source position in unoptimized code.
10496 int position = frame_inspector.GetSourcePosition();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010497
ulan@chromium.org967e2702012-02-28 09:49:15 +000010498 // Check for constructor frame.
10499 bool constructor = frame_inspector.IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010500
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010501 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010502 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010503 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010504 Handle<ScopeInfo> scope_info(shared->scope_info());
10505 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010506
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010507 // Get the locals names and values into a temporary array.
10508 //
10509 // TODO(1240907): Hide compiler-introduced stack variables
10510 // (e.g. .result)? For users of the debugger, they will probably be
10511 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010512 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010513 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010514
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010515 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010516 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010517 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010518 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010519 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010520 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010521 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010522 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010523 // Get the context containing declarations.
10524 Handle<Context> context(
10525 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010526 for (; i < scope_info->LocalCount(); ++i) {
10527 Handle<String> name(scope_info->LocalName(i));
10528 VariableMode mode;
10529 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010530 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010531 locals->set(i * 2 + 1, context->get(
10532 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010533 }
10534 }
10535
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010536 // Check whether this frame is positioned at return. If not top
10537 // frame or if the frame is optimized it cannot be at a return.
10538 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010539 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010540 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010541 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010542
10543 // If positioned just before return find the value to be returned and add it
10544 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010545 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010546 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010547 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010548 Address internal_frame_sp = NULL;
10549 while (!it2.done()) {
10550 if (it2.frame()->is_internal()) {
10551 internal_frame_sp = it2.frame()->sp();
10552 } else {
10553 if (it2.frame()->is_java_script()) {
10554 if (it2.frame()->id() == it.frame()->id()) {
10555 // The internal frame just before the JavaScript frame contains the
10556 // value to return on top. A debug break at return will create an
10557 // internal frame to store the return value (eax/rax/r0) before
10558 // entering the debug break exit frame.
10559 if (internal_frame_sp != NULL) {
10560 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010561 Handle<Object>(Memory::Object_at(internal_frame_sp),
10562 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010563 break;
10564 }
10565 }
10566 }
10567
10568 // Indicate that the previous frame was not an internal frame.
10569 internal_frame_sp = NULL;
10570 }
10571 it2.Advance();
10572 }
10573 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010574
10575 // Now advance to the arguments adapter frame (if any). It contains all
10576 // the provided parameters whereas the function frame always have the number
10577 // of arguments matching the functions parameters. The rest of the
10578 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010579 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010580 it.AdvanceToArgumentsFrame();
10581 frame_inspector.SetArgumentsFrame(it.frame());
10582 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010583
10584 // Find the number of arguments to fill. At least fill the number of
10585 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010586 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010587 if (argument_count < frame_inspector.GetParametersCount()) {
10588 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010589 }
10590
10591 // Calculate the size of the result.
10592 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010593 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010594 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010595 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010596
10597 // Add the frame id.
10598 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10599
10600 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010601 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010602
10603 // Add the arguments count.
10604 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10605
10606 // Add the locals count
10607 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010608 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010609
10610 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010611 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010612 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10613 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010614 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010615 }
10616
10617 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010618 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010619
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010620 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010621 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010622
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010623 // Add flags to indicate information on whether this frame is
10624 // bit 0: invoked in the debugger context.
10625 // bit 1: optimized frame.
10626 // bit 2: inlined in optimized frame
10627 int flags = 0;
10628 if (*save->context() == *isolate->debug()->debug_context()) {
10629 flags |= 1 << 0;
10630 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010631 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010632 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010633 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010634 }
10635 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010636
10637 // Fill the dynamic part.
10638 int details_index = kFrameDetailsFirstDynamicIndex;
10639
10640 // Add arguments name and value.
10641 for (int i = 0; i < argument_count; i++) {
10642 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010643 if (i < scope_info->ParameterCount()) {
10644 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010645 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010646 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010647 }
10648
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010649 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010650 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010651 // Get the value from the stack.
10652 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010653 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010654 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010655 }
10656 }
10657
10658 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010659 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010660 details->set(details_index++, locals->get(i));
10661 }
10662
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010663 // Add the value being returned.
10664 if (at_return) {
10665 details->set(details_index++, *return_value);
10666 }
10667
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010668 // Add the receiver (same as in function frame).
10669 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10670 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010671 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010672 if (!receiver->IsJSObject() &&
10673 shared->is_classic_mode() &&
10674 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010675 // If the receiver is not a JSObject and the function is not a
10676 // builtin or strict-mode we have hit an optimization where a
10677 // value object is not converted into a wrapped JS objects. To
10678 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010679 // by creating correct wrapper object based on the calling frame's
10680 // global context.
10681 it.Advance();
10682 Handle<Context> calling_frames_global_context(
10683 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010684 receiver =
10685 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010686 }
10687 details->set(kFrameDetailsReceiverIndex, *receiver);
10688
10689 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010690 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010691}
10692
10693
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010694// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010695static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010696 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010697 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010698 Handle<Context> context,
10699 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010700 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010701 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
10702 VariableMode mode;
10703 InitializationFlag init_flag;
10704 int context_index = scope_info->ContextSlotIndex(
10705 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010706
whesse@chromium.org7b260152011-06-20 15:33:18 +000010707 RETURN_IF_EMPTY_HANDLE_VALUE(
10708 isolate,
10709 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010710 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000010711 Handle<Object>(context->get(context_index), isolate),
10712 NONE,
10713 kNonStrictMode),
10714 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010715 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010716
10717 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010718}
10719
10720
10721// Create a plain JSObject which materializes the local scope for the specified
10722// frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010723static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010724 Isolate* isolate,
10725 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010726 FrameInspector* frame_inspector) {
10727 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010728 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010729 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010730
10731 // Allocate and initialize a JSObject with all the arguments, stack locals
10732 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010733 Handle<JSObject> local_scope =
10734 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010735
10736 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010737 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010738 Handle<Object> value(
10739 i < frame_inspector->GetParametersCount() ?
10740 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value());
10741
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010742 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010743 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010744 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010745 Handle<String>(scope_info->ParameterName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010746 value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010747 NONE,
10748 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010749 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010750 }
10751
10752 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010753 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010754 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010755 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010756 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010757 Handle<String>(scope_info->StackLocalName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010758 Handle<Object>(frame_inspector->GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010759 NONE,
10760 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010761 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010762 }
10763
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010764 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010765 // Third fill all context locals.
10766 Handle<Context> frame_context(Context::cast(frame->context()));
10767 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010768 if (!CopyContextLocalsToScopeObject(
10769 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010770 return Handle<JSObject>();
10771 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010772
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010773 // Finally copy any properties from the function context extension.
10774 // These will be variables introduced by eval.
10775 if (function_context->closure() == *function) {
10776 if (function_context->has_extension() &&
10777 !function_context->IsGlobalContext()) {
10778 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010779 bool threw = false;
10780 Handle<FixedArray> keys =
10781 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10782 if (threw) return Handle<JSObject>();
10783
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010784 for (int i = 0; i < keys->length(); i++) {
10785 // Names of variables introduced by eval are strings.
10786 ASSERT(keys->get(i)->IsString());
10787 Handle<String> key(String::cast(keys->get(i)));
10788 RETURN_IF_EMPTY_HANDLE_VALUE(
10789 isolate,
10790 SetProperty(local_scope,
10791 key,
10792 GetProperty(ext, key),
10793 NONE,
10794 kNonStrictMode),
10795 Handle<JSObject>());
10796 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010797 }
10798 }
10799 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010800
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010801 return local_scope;
10802}
10803
10804
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010805static Handle<JSObject> MaterializeLocalScope(
10806 Isolate* isolate,
10807 JavaScriptFrame* frame,
10808 int inlined_jsframe_index) {
10809 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
10810 return MaterializeLocalScopeWithFrameInspector(isolate,
10811 frame,
10812 &frame_inspector);
10813}
10814
10815
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010816// Create a plain JSObject which materializes the closure content for the
10817// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010818static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10819 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010820 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010821
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010822 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010823 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010824
ulan@chromium.org2efb9002012-01-19 15:36:35 +000010825 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010826 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010827 Handle<JSObject> closure_scope =
10828 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010829
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010830 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010831 if (!CopyContextLocalsToScopeObject(
10832 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010833 return Handle<JSObject>();
10834 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010835
10836 // Finally copy any properties from the function context extension. This will
10837 // be variables introduced by eval.
10838 if (context->has_extension()) {
10839 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010840 bool threw = false;
10841 Handle<FixedArray> keys =
10842 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
10843 if (threw) return Handle<JSObject>();
10844
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010845 for (int i = 0; i < keys->length(); i++) {
10846 // Names of variables introduced by eval are strings.
10847 ASSERT(keys->get(i)->IsString());
10848 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010849 RETURN_IF_EMPTY_HANDLE_VALUE(
10850 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010851 SetProperty(closure_scope,
10852 key,
10853 GetProperty(ext, key),
10854 NONE,
10855 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010856 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010857 }
10858 }
10859
10860 return closure_scope;
10861}
10862
10863
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010864// Create a plain JSObject which materializes the scope for the specified
10865// catch context.
10866static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10867 Handle<Context> context) {
10868 ASSERT(context->IsCatchContext());
10869 Handle<String> name(String::cast(context->extension()));
10870 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10871 Handle<JSObject> catch_scope =
10872 isolate->factory()->NewJSObject(isolate->object_function());
10873 RETURN_IF_EMPTY_HANDLE_VALUE(
10874 isolate,
10875 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10876 Handle<JSObject>());
10877 return catch_scope;
10878}
10879
10880
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010881// Create a plain JSObject which materializes the block scope for the specified
10882// block context.
10883static Handle<JSObject> MaterializeBlockScope(
10884 Isolate* isolate,
10885 Handle<Context> context) {
10886 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010887 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010888
10889 // Allocate and initialize a JSObject with all the arguments, stack locals
10890 // heap locals and extension properties of the debugged function.
10891 Handle<JSObject> block_scope =
10892 isolate->factory()->NewJSObject(isolate->object_function());
10893
10894 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010895 if (!CopyContextLocalsToScopeObject(
10896 isolate, scope_info, context, block_scope)) {
10897 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010898 }
10899
10900 return block_scope;
10901}
10902
10903
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010904// Create a plain JSObject which materializes the module scope for the specified
10905// module context.
10906static Handle<JSObject> MaterializeModuleScope(
10907 Isolate* isolate,
10908 Handle<Context> context) {
10909 ASSERT(context->IsModuleContext());
10910 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
10911
10912 // Allocate and initialize a JSObject with all the members of the debugged
10913 // module.
10914 Handle<JSObject> module_scope =
10915 isolate->factory()->NewJSObject(isolate->object_function());
10916
10917 // Fill all context locals.
10918 if (!CopyContextLocalsToScopeObject(
10919 isolate, scope_info, context, module_scope)) {
10920 return Handle<JSObject>();
10921 }
10922
10923 return module_scope;
10924}
10925
10926
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010927// Iterate over the actual scopes visible from a stack frame. The iteration
10928// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010929// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010930// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010931class ScopeIterator {
10932 public:
10933 enum ScopeType {
10934 ScopeTypeGlobal = 0,
10935 ScopeTypeLocal,
10936 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010937 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010938 ScopeTypeCatch,
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000010939 ScopeTypeBlock,
10940 ScopeTypeModule
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010941 };
10942
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010943 ScopeIterator(Isolate* isolate,
10944 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010945 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010946 : isolate_(isolate),
10947 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010948 inlined_jsframe_index_(inlined_jsframe_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010949 function_(JSFunction::cast(frame->function())),
10950 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010951 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010952
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010953 // Catch the case when the debugger stops in an internal function.
10954 Handle<SharedFunctionInfo> shared_info(function_->shared());
10955 Handle<ScopeInfo> scope_info(shared_info->scope_info());
10956 if (shared_info->script() == isolate->heap()->undefined_value()) {
10957 while (context_->closure() == *function_) {
10958 context_ = Handle<Context>(context_->previous(), isolate_);
10959 }
10960 return;
10961 }
10962
10963 // Get the debug info (create it if it does not exist).
10964 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
10965 // Return if ensuring debug info failed.
10966 return;
10967 }
10968 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
10969
10970 // Find the break point where execution has stopped.
10971 BreakLocationIterator break_location_iterator(debug_info,
10972 ALL_BREAK_LOCATIONS);
10973 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
10974 if (break_location_iterator.IsExit()) {
10975 // We are within the return sequence. At the momemt it is not possible to
10976 // get a source position which is consistent with the current scope chain.
10977 // Thus all nested with, catch and block contexts are skipped and we only
10978 // provide the function scope.
10979 if (scope_info->HasContext()) {
10980 context_ = Handle<Context>(context_->declaration_context(), isolate_);
10981 } else {
10982 while (context_->closure() == *function_) {
10983 context_ = Handle<Context>(context_->previous(), isolate_);
10984 }
10985 }
10986 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
10987 } else {
10988 // Reparse the code and analyze the scopes.
10989 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
10990 Handle<Script> script(Script::cast(shared_info->script()));
10991 Scope* scope = NULL;
10992
10993 // Check whether we are in global, eval or function code.
10994 Handle<ScopeInfo> scope_info(shared_info->scope_info());
10995 if (scope_info->Type() != FUNCTION_SCOPE) {
10996 // Global or eval code.
10997 CompilationInfo info(script);
10998 if (scope_info->Type() == GLOBAL_SCOPE) {
10999 info.MarkAsGlobal();
11000 } else {
11001 ASSERT(scope_info->Type() == EVAL_SCOPE);
11002 info.MarkAsEval();
11003 info.SetCallingContext(Handle<Context>(function_->context()));
11004 }
11005 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11006 scope = info.function()->scope();
11007 }
11008 } else {
11009 // Function code
11010 CompilationInfo info(shared_info);
11011 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11012 scope = info.function()->scope();
11013 }
11014 }
11015
11016 // Retrieve the scope chain for the current position.
11017 if (scope != NULL) {
11018 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11019 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11020 } else {
11021 // A failed reparse indicates that the preparser has diverged from the
11022 // parser or that the preparse data given to the initial parse has been
11023 // faulty. We fail in debug mode but in release mode we only provide the
11024 // information we get from the context chain but nothing about
11025 // completely stack allocated scopes or stack allocated locals.
11026 UNREACHABLE();
11027 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011028 }
11029 }
11030
11031 // More scopes?
11032 bool Done() { return context_.is_null(); }
11033
11034 // Move to the next scope.
11035 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011036 ScopeType scope_type = Type();
11037 if (scope_type == ScopeTypeGlobal) {
11038 // The global scope is always the last in the chain.
11039 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011040 context_ = Handle<Context>();
11041 return;
11042 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011043 if (nested_scope_chain_.is_empty()) {
11044 context_ = Handle<Context>(context_->previous(), isolate_);
11045 } else {
11046 if (nested_scope_chain_.last()->HasContext()) {
11047 ASSERT(context_->previous() != NULL);
11048 context_ = Handle<Context>(context_->previous(), isolate_);
11049 }
11050 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011051 }
11052 }
11053
11054 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011055 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011056 if (!nested_scope_chain_.is_empty()) {
11057 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11058 switch (scope_info->Type()) {
11059 case FUNCTION_SCOPE:
11060 ASSERT(context_->IsFunctionContext() ||
11061 !scope_info->HasContext());
11062 return ScopeTypeLocal;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011063 case MODULE_SCOPE:
11064 ASSERT(context_->IsModuleContext());
11065 return ScopeTypeModule;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011066 case GLOBAL_SCOPE:
11067 ASSERT(context_->IsGlobalContext());
11068 return ScopeTypeGlobal;
11069 case WITH_SCOPE:
11070 ASSERT(context_->IsWithContext());
11071 return ScopeTypeWith;
11072 case CATCH_SCOPE:
11073 ASSERT(context_->IsCatchContext());
11074 return ScopeTypeCatch;
11075 case BLOCK_SCOPE:
11076 ASSERT(!scope_info->HasContext() ||
11077 context_->IsBlockContext());
11078 return ScopeTypeBlock;
11079 case EVAL_SCOPE:
11080 UNREACHABLE();
11081 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011082 }
11083 if (context_->IsGlobalContext()) {
11084 ASSERT(context_->global()->IsGlobalObject());
11085 return ScopeTypeGlobal;
11086 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011087 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011088 return ScopeTypeClosure;
11089 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011090 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011091 return ScopeTypeCatch;
11092 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011093 if (context_->IsBlockContext()) {
11094 return ScopeTypeBlock;
11095 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011096 if (context_->IsModuleContext()) {
11097 return ScopeTypeModule;
11098 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011099 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011100 return ScopeTypeWith;
11101 }
11102
11103 // Return the JavaScript object with the content of the current scope.
11104 Handle<JSObject> ScopeObject() {
11105 switch (Type()) {
11106 case ScopeIterator::ScopeTypeGlobal:
11107 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011108 case ScopeIterator::ScopeTypeLocal:
11109 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011110 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011111 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011112 case ScopeIterator::ScopeTypeWith:
11113 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011114 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11115 case ScopeIterator::ScopeTypeCatch:
11116 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011117 case ScopeIterator::ScopeTypeClosure:
11118 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011119 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011120 case ScopeIterator::ScopeTypeBlock:
11121 return MaterializeBlockScope(isolate_, CurrentContext());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011122 case ScopeIterator::ScopeTypeModule:
11123 return MaterializeModuleScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011124 }
11125 UNREACHABLE();
11126 return Handle<JSObject>();
11127 }
11128
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011129 Handle<ScopeInfo> CurrentScopeInfo() {
11130 if (!nested_scope_chain_.is_empty()) {
11131 return nested_scope_chain_.last();
11132 } else if (context_->IsBlockContext()) {
11133 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11134 } else if (context_->IsFunctionContext()) {
11135 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11136 }
11137 return Handle<ScopeInfo>::null();
11138 }
11139
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011140 // Return the context for this scope. For the local context there might not
11141 // be an actual context.
11142 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011143 if (Type() == ScopeTypeGlobal ||
11144 nested_scope_chain_.is_empty()) {
11145 return context_;
11146 } else if (nested_scope_chain_.last()->HasContext()) {
11147 return context_;
11148 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011149 return Handle<Context>();
11150 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011151 }
11152
11153#ifdef DEBUG
11154 // Debug print of the content of the current scope.
11155 void DebugPrint() {
11156 switch (Type()) {
11157 case ScopeIterator::ScopeTypeGlobal:
11158 PrintF("Global:\n");
11159 CurrentContext()->Print();
11160 break;
11161
11162 case ScopeIterator::ScopeTypeLocal: {
11163 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011164 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011165 if (!CurrentContext().is_null()) {
11166 CurrentContext()->Print();
11167 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011168 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011169 if (extension->IsJSContextExtensionObject()) {
11170 extension->Print();
11171 }
11172 }
11173 }
11174 break;
11175 }
11176
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011177 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011178 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011179 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011180 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011181
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011182 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011183 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011184 CurrentContext()->extension()->Print();
11185 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011186 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011187
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011188 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011189 PrintF("Closure:\n");
11190 CurrentContext()->Print();
11191 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011192 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011193 if (extension->IsJSContextExtensionObject()) {
11194 extension->Print();
11195 }
11196 }
11197 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011198
11199 default:
11200 UNREACHABLE();
11201 }
11202 PrintF("\n");
11203 }
11204#endif
11205
11206 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011207 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011208 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011209 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011210 Handle<JSFunction> function_;
11211 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011212 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011213
11214 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11215};
11216
11217
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011218RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011219 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011220 ASSERT(args.length() == 2);
11221
11222 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011223 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011224 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11225 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011226 if (!maybe_check->ToObject(&check)) return maybe_check;
11227 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011228 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011229
11230 // Get the frame where the debugging is performed.
11231 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011232 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011233 JavaScriptFrame* frame = it.frame();
11234
11235 // Count the visible scopes.
11236 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011237 for (ScopeIterator it(isolate, frame, 0);
11238 !it.Done();
11239 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011240 n++;
11241 }
11242
11243 return Smi::FromInt(n);
11244}
11245
11246
11247static const int kScopeDetailsTypeIndex = 0;
11248static const int kScopeDetailsObjectIndex = 1;
11249static const int kScopeDetailsSize = 2;
11250
11251// Return an array with scope details
11252// args[0]: number: break id
11253// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011254// args[2]: number: inlined frame index
11255// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011256//
11257// The array returned contains the following information:
11258// 0: Scope type
11259// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011260RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011261 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011262 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011263
11264 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011265 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011266 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11267 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011268 if (!maybe_check->ToObject(&check)) return maybe_check;
11269 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011270 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011271 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011272 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011273
11274 // Get the frame where the debugging is performed.
11275 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011276 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011277 JavaScriptFrame* frame = frame_it.frame();
11278
11279 // Find the requested scope.
11280 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011281 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011282 for (; !it.Done() && n < index; it.Next()) {
11283 n++;
11284 }
11285 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011286 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011287 }
11288
11289 // Calculate the size of the result.
11290 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011291 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011292
11293 // Fill in scope details.
11294 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011295 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011296 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011297 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011298
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011299 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011300}
11301
11302
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011303RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011304 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011305 ASSERT(args.length() == 0);
11306
11307#ifdef DEBUG
11308 // Print the scopes for the top frame.
11309 StackFrameLocator locator;
11310 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011311 for (ScopeIterator it(isolate, frame, 0);
11312 !it.Done();
11313 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011314 it.DebugPrint();
11315 }
11316#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011317 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011318}
11319
11320
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011321RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011322 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011323 ASSERT(args.length() == 1);
11324
11325 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011326 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011327 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11328 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011329 if (!maybe_result->ToObject(&result)) return maybe_result;
11330 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011331
11332 // Count all archived V8 threads.
11333 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011334 for (ThreadState* thread =
11335 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011336 thread != NULL;
11337 thread = thread->Next()) {
11338 n++;
11339 }
11340
11341 // Total number of threads is current thread and archived threads.
11342 return Smi::FromInt(n + 1);
11343}
11344
11345
11346static const int kThreadDetailsCurrentThreadIndex = 0;
11347static const int kThreadDetailsThreadIdIndex = 1;
11348static const int kThreadDetailsSize = 2;
11349
11350// Return an array with thread details
11351// args[0]: number: break id
11352// args[1]: number: thread index
11353//
11354// The array returned contains the following information:
11355// 0: Is current thread?
11356// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011357RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011358 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011359 ASSERT(args.length() == 2);
11360
11361 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011362 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011363 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11364 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011365 if (!maybe_check->ToObject(&check)) return maybe_check;
11366 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011367 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11368
11369 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011370 Handle<FixedArray> details =
11371 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011372
11373 // Thread index 0 is current thread.
11374 if (index == 0) {
11375 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011376 details->set(kThreadDetailsCurrentThreadIndex,
11377 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011378 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011379 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011380 } else {
11381 // Find the thread with the requested index.
11382 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011383 ThreadState* thread =
11384 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011385 while (index != n && thread != NULL) {
11386 thread = thread->Next();
11387 n++;
11388 }
11389 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011390 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011391 }
11392
11393 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011394 details->set(kThreadDetailsCurrentThreadIndex,
11395 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011396 details->set(kThreadDetailsThreadIdIndex,
11397 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011398 }
11399
11400 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011401 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011402}
11403
11404
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011405// Sets the disable break state
11406// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011407RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011408 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011409 ASSERT(args.length() == 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011410 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011411 isolate->debug()->set_disable_break(disable_break);
11412 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011413}
11414
11415
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011416RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011417 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011418 ASSERT(args.length() == 1);
11419
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011420 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011421 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011422 // Find the number of break points
11423 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011424 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011425 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011426 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011427 Handle<FixedArray>::cast(break_locations));
11428}
11429
11430
11431// Set a break point in a function
11432// args[0]: function
11433// args[1]: number: break source position (within the function source)
11434// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011435RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011436 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011437 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011438 CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011439 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011440 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11441 RUNTIME_ASSERT(source_position >= 0);
11442 Handle<Object> break_point_object_arg = args.at<Object>(2);
11443
11444 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011445 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11446 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011447
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011448 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011449}
11450
11451
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011452Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11453 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011454 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011455 // Iterate the heap looking for SharedFunctionInfo generated from the
11456 // script. The inner most SharedFunctionInfo containing the source position
11457 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011458 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011459 // which is found is not compiled it is compiled and the heap is iterated
11460 // again as the compilation might create inner functions from the newly
11461 // compiled function and the actual requested break point might be in one of
11462 // these functions.
11463 bool done = false;
11464 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011465 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011466 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011467 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011468 { // Extra scope for iterator and no-allocation.
11469 isolate->heap()->EnsureHeapIsIterable();
11470 AssertNoAllocation no_alloc_during_heap_iteration;
11471 HeapIterator iterator;
11472 for (HeapObject* obj = iterator.next();
11473 obj != NULL; obj = iterator.next()) {
11474 if (obj->IsSharedFunctionInfo()) {
11475 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11476 if (shared->script() == *script) {
11477 // If the SharedFunctionInfo found has the requested script data and
11478 // contains the source position it is a candidate.
11479 int start_position = shared->function_token_position();
11480 if (start_position == RelocInfo::kNoPosition) {
11481 start_position = shared->start_position();
11482 }
11483 if (start_position <= position &&
11484 position <= shared->end_position()) {
11485 // If there is no candidate or this function is within the current
11486 // candidate this is the new candidate.
11487 if (target.is_null()) {
11488 target_start_position = start_position;
11489 target = shared;
11490 } else {
11491 if (target_start_position == start_position &&
11492 shared->end_position() == target->end_position()) {
11493 // If a top-level function contain only one function
11494 // declartion the source for the top-level and the
11495 // function is the same. In that case prefer the non
11496 // top-level function.
11497 if (!shared->is_toplevel()) {
11498 target_start_position = start_position;
11499 target = shared;
11500 }
11501 } else if (target_start_position <= start_position &&
11502 shared->end_position() <= target->end_position()) {
11503 // This containment check includes equality as a function
11504 // inside a top-level function can share either start or end
11505 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011506 target_start_position = start_position;
11507 target = shared;
11508 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011509 }
11510 }
11511 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011512 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011513 } // End for loop.
11514 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011515
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011516 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011517 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011518 }
11519
11520 // If the candidate found is compiled we are done. NOTE: when lazy
11521 // compilation of inner functions is introduced some additional checking
11522 // needs to be done here to compile inner functions.
11523 done = target->is_compiled();
11524 if (!done) {
11525 // If the candidate is not compiled compile it to reveal any inner
11526 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011527 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011528 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011529 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011530
11531 return *target;
11532}
11533
11534
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011535// Changes the state of a break point in a script and returns source position
11536// where break point was set. NOTE: Regarding performance see the NOTE for
11537// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011538// args[0]: script to set break point in
11539// args[1]: number: break source position (within the script source)
11540// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011541RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011542 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011543 ASSERT(args.length() == 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011544 CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011545 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11546 RUNTIME_ASSERT(source_position >= 0);
11547 Handle<Object> break_point_object_arg = args.at<Object>(2);
11548
11549 // Get the script from the script wrapper.
11550 RUNTIME_ASSERT(wrapper->value()->IsScript());
11551 Handle<Script> script(Script::cast(wrapper->value()));
11552
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011553 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011554 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011555 if (!result->IsUndefined()) {
11556 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11557 // Find position within function. The script position might be before the
11558 // source position of the first function.
11559 int position;
11560 if (shared->start_position() > source_position) {
11561 position = 0;
11562 } else {
11563 position = source_position - shared->start_position();
11564 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011565 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011566 position += shared->start_position();
11567 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011568 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011569 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011570}
11571
11572
11573// Clear a break point
11574// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011575RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011576 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011577 ASSERT(args.length() == 1);
11578 Handle<Object> break_point_object_arg = args.at<Object>(0);
11579
11580 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011581 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011582
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011583 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011584}
11585
11586
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011587// Change the state of break on exceptions.
11588// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11589// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011590RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011591 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011592 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011593 RUNTIME_ASSERT(args[0]->IsNumber());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011594 CONVERT_BOOLEAN_ARG_CHECKED(enable, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011595
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011596 // If the number doesn't match an enum value, the ChangeBreakOnException
11597 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011598 ExceptionBreakType type =
11599 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011600 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011601 isolate->debug()->ChangeBreakOnException(type, enable);
11602 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011603}
11604
11605
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011606// Returns the state of break on exceptions
11607// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011608RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011609 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011610 ASSERT(args.length() == 1);
11611 RUNTIME_ASSERT(args[0]->IsNumber());
11612
11613 ExceptionBreakType type =
11614 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011615 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011616 return Smi::FromInt(result);
11617}
11618
11619
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011620// Prepare for stepping
11621// args[0]: break id for checking execution state
11622// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011623// args[2]: number of times to perform the step, for step out it is the number
11624// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011625RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011626 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011627 ASSERT(args.length() == 3);
11628 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011629 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011630 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11631 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011632 if (!maybe_check->ToObject(&check)) return maybe_check;
11633 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011634 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011635 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011636 }
11637
11638 // Get the step action and check validity.
11639 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11640 if (step_action != StepIn &&
11641 step_action != StepNext &&
11642 step_action != StepOut &&
11643 step_action != StepInMin &&
11644 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011645 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011646 }
11647
11648 // Get the number of steps.
11649 int step_count = NumberToInt32(args[2]);
11650 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011651 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011652 }
11653
ager@chromium.orga1645e22009-09-09 19:27:10 +000011654 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011655 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011656
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011657 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011658 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11659 step_count);
11660 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011661}
11662
11663
11664// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011665RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011666 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011667 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011668 isolate->debug()->ClearStepping();
11669 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011670}
11671
11672
11673// Creates a copy of the with context chain. The copy of the context chain is
11674// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011675static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11676 Handle<JSFunction> function,
11677 Handle<Context> base,
11678 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011679 int inlined_jsframe_index) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011680 HandleScope scope(isolate);
11681 List<Handle<ScopeInfo> > scope_chain;
11682 List<Handle<Context> > context_chain;
11683
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011684 ScopeIterator it(isolate, frame, inlined_jsframe_index);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011685 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11686 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11687 ASSERT(!it.Done());
11688 scope_chain.Add(it.CurrentScopeInfo());
11689 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011690 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011691
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011692 // At the end of the chain. Return the base context to link to.
11693 Handle<Context> context = base;
11694
11695 // Iteratively copy and or materialize the nested contexts.
11696 while (!scope_chain.is_empty()) {
11697 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
11698 Handle<Context> current = context_chain.RemoveLast();
11699 ASSERT(!(scope_info->HasContext() & current.is_null()));
11700
11701 if (scope_info->Type() == CATCH_SCOPE) {
11702 Handle<String> name(String::cast(current->extension()));
11703 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11704 context =
11705 isolate->factory()->NewCatchContext(function,
11706 context,
11707 name,
11708 thrown_object);
11709 } else if (scope_info->Type() == BLOCK_SCOPE) {
11710 // Materialize the contents of the block scope into a JSObject.
11711 Handle<JSObject> block_scope_object =
11712 MaterializeBlockScope(isolate, current);
11713 if (block_scope_object.is_null()) {
11714 return Handle<Context>::null();
11715 }
11716 // Allocate a new function context for the debug evaluation and set the
11717 // extension object.
11718 Handle<Context> new_context =
11719 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11720 function);
11721 new_context->set_extension(*block_scope_object);
11722 new_context->set_previous(*context);
11723 context = new_context;
11724 } else {
11725 ASSERT(scope_info->Type() == WITH_SCOPE);
11726 ASSERT(current->IsWithContext());
11727 Handle<JSObject> extension(JSObject::cast(current->extension()));
11728 context =
11729 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000011730 }
erikcorry0ad885c2011-11-21 13:51:57 +000011731 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011732
11733 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011734}
11735
11736
11737// Helper function to find or create the arguments object for
11738// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011739static Handle<Object> GetArgumentsObject(Isolate* isolate,
11740 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011741 FrameInspector* frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011742 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011743 Handle<Context> function_context) {
11744 // Try to find the value of 'arguments' to pass as parameter. If it is not
11745 // found (that is the debugged function does not reference 'arguments' and
11746 // does not support eval) then create an 'arguments' object.
11747 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011748 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011749 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011750 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011751 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011752 }
11753 }
11754
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011755 if (scope_info->HasHeapAllocatedLocals()) {
11756 VariableMode mode;
11757 InitializationFlag init_flag;
11758 index = scope_info->ContextSlotIndex(
11759 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011760 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011761 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011762 }
11763 }
11764
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011765 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
11766 int length = frame_inspector->GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011767 Handle<JSObject> arguments =
11768 isolate->factory()->NewArgumentsObject(function, length);
11769 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011770
11771 AssertNoAllocation no_gc;
11772 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011773 for (int i = 0; i < length; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011774 array->set(i, frame_inspector->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011775 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011776 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011777 return arguments;
11778}
11779
11780
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011781static const char kSourceStr[] =
11782 "(function(arguments,__source__){return eval(__source__);})";
11783
11784
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011785// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011786// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011787// extension part has all the parameters and locals of the function on the
11788// stack frame. A function which calls eval with the code to evaluate is then
11789// compiled in this context and called in this context. As this context
11790// replaces the context of the function on the stack frame a new (empty)
11791// function is created as well to be used as the closure for the context.
11792// This function and the context acts as replacements for the function on the
11793// stack frame presenting the same view of the values of parameters and
11794// local variables as if the piece of JavaScript was evaluated at the point
11795// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011796RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011797 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011798
11799 // Check the execution state and decode arguments frame and source to be
11800 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011801 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011802 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011803 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11804 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011805 if (!maybe_check_result->ToObject(&check_result)) {
11806 return maybe_check_result;
11807 }
11808 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011809 CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011810 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011811 CONVERT_ARG_HANDLE_CHECKED(String, source, 3);
11812 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011813 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011814
11815 // Handle the processing of break.
11816 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011817
11818 // Get the frame where the debugging is performed.
11819 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011820 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011821 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011822 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11823 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011824 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011825
11826 // Traverse the saved contexts chain to find the active context for the
11827 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011828 SaveContext* save = FindSavedContextForFrame(isolate, frame);
11829
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011830 SaveContext savex(isolate);
11831 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011832
11833 // Create the (empty) function replacing the function on the stack frame for
11834 // the purpose of evaluating in the context created below. It is important
11835 // that this function does not describe any parameters and local variables
11836 // in the context. If it does then this will cause problems with the lookup
11837 // in Context::Lookup, where context slots for parameters and local variables
11838 // are looked at before the extension object.
11839 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011840 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11841 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011842 go_between->set_context(function->context());
11843#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011844 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
11845 ASSERT(go_between_scope_info->ParameterCount() == 0);
11846 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011847#endif
11848
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011849 // Materialize the content of the local scope into a JSObject.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011850 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
11851 isolate, frame, &frame_inspector);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011852 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011853
11854 // Allocate a new context for the debug evaluation and set the extension
11855 // object build.
11856 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011857 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11858 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011859 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011860 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011861 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011862 Handle<Context> function_context;
11863 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011864 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011865 function_context = Handle<Context>(frame_context->declaration_context());
11866 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011867 context = CopyNestedScopeContextChain(isolate,
11868 go_between,
11869 context,
11870 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011871 inlined_jsframe_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011872
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011873 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011874 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011875 context =
11876 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011877 }
11878
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011879 // Wrap the evaluation statement in a new function compiled in the newly
11880 // created context. The function has one parameter which has to be called
11881 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011882 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011883 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011884
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011885 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011886 isolate->factory()->NewStringFromAscii(
11887 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011888
11889 // Currently, the eval code will be executed in non-strict mode,
11890 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011891 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011892 Compiler::CompileEval(function_source,
11893 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011894 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011895 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011896 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011897 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011898 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011899 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011900
11901 // Invoke the result of the compilation to get the evaluation function.
11902 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011903 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011904 Handle<Object> evaluation_function =
11905 Execution::Call(compiled_function, receiver, 0, NULL,
11906 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011907 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011908
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011909 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011910 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011911 &frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011912 scope_info,
11913 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011914
11915 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011916 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011917 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011918 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
11919 receiver,
11920 ARRAY_SIZE(argv),
11921 argv,
11922 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011923 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011924
11925 // Skip the global proxy as it has no properties and always delegates to the
11926 // real global object.
11927 if (result->IsJSGlobalProxy()) {
11928 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11929 }
11930
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011931 return *result;
11932}
11933
11934
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011935RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011936 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011937
11938 // Check the execution state and decode arguments frame and source to be
11939 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011940 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011941 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011942 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11943 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011944 if (!maybe_check_result->ToObject(&check_result)) {
11945 return maybe_check_result;
11946 }
11947 }
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011948 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
11949 CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011950 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011951
11952 // Handle the processing of break.
11953 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011954
11955 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011956 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011957 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011958 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011959 top = top->prev();
11960 }
11961 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011962 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011963 }
11964
11965 // Get the global context now set to the top context from before the
11966 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011967 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011968
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011969 bool is_global = true;
11970
11971 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000011972 // Create a new with context with the additional context information between
11973 // the context of the debugged function and the eval code to be executed.
11974 context = isolate->factory()->NewWithContext(
11975 Handle<JSFunction>(context->closure()),
11976 context,
11977 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011978 is_global = false;
11979 }
11980
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011981 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011982 // Currently, the eval code will be executed in non-strict mode,
11983 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011984 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011985 Compiler::CompileEval(source,
11986 context,
11987 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011988 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011989 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011990 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011991 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011992 Handle<JSFunction>(
11993 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11994 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011995
11996 // Invoke the result of the compilation to get the evaluation function.
11997 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011998 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011999 Handle<Object> result =
12000 Execution::Call(compiled_function, receiver, 0, NULL,
12001 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012002 // Clear the oneshot breakpoints so that the debugger does not step further.
12003 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012004 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012005 return *result;
12006}
12007
12008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012009RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012010 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012011 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012012
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012013 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012014 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012015
12016 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012017 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012018 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12019 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12020 // because using
12021 // instances->set(i, *GetScriptWrapper(script))
12022 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012023 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012024 Handle<JSValue> wrapper = GetScriptWrapper(script);
12025 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012026 }
12027
12028 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012029 Handle<JSObject> result =
12030 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012031 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012032 return *result;
12033}
12034
12035
12036// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012037static int DebugReferencedBy(HeapIterator* iterator,
12038 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012039 Object* instance_filter, int max_references,
12040 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012041 JSFunction* arguments_function) {
12042 NoHandleAllocation ha;
12043 AssertNoAllocation no_alloc;
12044
12045 // Iterate the heap.
12046 int count = 0;
12047 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012048 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012049 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012050 (max_references == 0 || count < max_references)) {
12051 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012052 if (heap_obj->IsJSObject()) {
12053 // Skip context extension objects and argument arrays as these are
12054 // checked in the context of functions using them.
12055 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012056 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012057 obj->map()->constructor() == arguments_function) {
12058 continue;
12059 }
12060
12061 // Check if the JS object has a reference to the object looked for.
12062 if (obj->ReferencesObject(target)) {
12063 // Check instance filter if supplied. This is normally used to avoid
12064 // references from mirror objects (see Runtime_IsInPrototypeChain).
12065 if (!instance_filter->IsUndefined()) {
12066 Object* V = obj;
12067 while (true) {
12068 Object* prototype = V->GetPrototype();
12069 if (prototype->IsNull()) {
12070 break;
12071 }
12072 if (instance_filter == prototype) {
12073 obj = NULL; // Don't add this object.
12074 break;
12075 }
12076 V = prototype;
12077 }
12078 }
12079
12080 if (obj != NULL) {
12081 // Valid reference found add to instance array if supplied an update
12082 // count.
12083 if (instances != NULL && count < instances_size) {
12084 instances->set(count, obj);
12085 }
12086 last = obj;
12087 count++;
12088 }
12089 }
12090 }
12091 }
12092
12093 // Check for circular reference only. This can happen when the object is only
12094 // referenced from mirrors and has a circular reference in which case the
12095 // object is not really alive and would have been garbage collected if not
12096 // referenced from the mirror.
12097 if (count == 1 && last == target) {
12098 count = 0;
12099 }
12100
12101 // Return the number of referencing objects found.
12102 return count;
12103}
12104
12105
12106// Scan the heap for objects with direct references to an object
12107// args[0]: the object to find references to
12108// args[1]: constructor function for instances to exclude (Mirror)
12109// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012110RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012111 ASSERT(args.length() == 3);
12112
12113 // First perform a full GC in order to avoid references from dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012114 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12115 "%DebugReferencedBy");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012116 // The heap iterator reserves the right to do a GC to make the heap iterable.
12117 // Due to the GC above we know it won't need to do that, but it seems cleaner
12118 // to get the heap iterator constructed before we start having unprotected
12119 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012120
12121 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012122 CONVERT_ARG_CHECKED(JSObject, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012123 Object* instance_filter = args[1];
12124 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12125 instance_filter->IsJSObject());
12126 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12127 RUNTIME_ASSERT(max_references >= 0);
12128
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012129
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012130 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012131 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012132 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012133 JSFunction* arguments_function =
12134 JSFunction::cast(arguments_boilerplate->map()->constructor());
12135
12136 // Get the number of referencing objects.
12137 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012138 HeapIterator heap_iterator;
12139 count = DebugReferencedBy(&heap_iterator,
12140 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012141 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012142
12143 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012144 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012145 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012146 if (!maybe_object->ToObject(&object)) return maybe_object;
12147 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012148 FixedArray* instances = FixedArray::cast(object);
12149
12150 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012151 // AllocateFixedArray above does not make the heap non-iterable.
12152 ASSERT(HEAP->IsHeapIterable());
12153 HeapIterator heap_iterator2;
12154 count = DebugReferencedBy(&heap_iterator2,
12155 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012156 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012157
12158 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012159 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012160 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012161 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012162 if (!maybe_result->ToObject(&result)) return maybe_result;
12163 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012164}
12165
12166
12167// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012168static int DebugConstructedBy(HeapIterator* iterator,
12169 JSFunction* constructor,
12170 int max_references,
12171 FixedArray* instances,
12172 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012173 AssertNoAllocation no_alloc;
12174
12175 // Iterate the heap.
12176 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012177 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012178 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012179 (max_references == 0 || count < max_references)) {
12180 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012181 if (heap_obj->IsJSObject()) {
12182 JSObject* obj = JSObject::cast(heap_obj);
12183 if (obj->map()->constructor() == constructor) {
12184 // Valid reference found add to instance array if supplied an update
12185 // count.
12186 if (instances != NULL && count < instances_size) {
12187 instances->set(count, obj);
12188 }
12189 count++;
12190 }
12191 }
12192 }
12193
12194 // Return the number of referencing objects found.
12195 return count;
12196}
12197
12198
12199// Scan the heap for objects constructed by a specific function.
12200// args[0]: the constructor to find instances of
12201// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012202RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012203 ASSERT(args.length() == 2);
12204
12205 // First perform a full GC in order to avoid dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012206 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12207 "%DebugConstructedBy");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012208
12209 // Check parameters.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012210 CONVERT_ARG_CHECKED(JSFunction, constructor, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012211 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12212 RUNTIME_ASSERT(max_references >= 0);
12213
12214 // Get the number of referencing objects.
12215 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012216 HeapIterator heap_iterator;
12217 count = DebugConstructedBy(&heap_iterator,
12218 constructor,
12219 max_references,
12220 NULL,
12221 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012222
12223 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012224 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012225 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012226 if (!maybe_object->ToObject(&object)) return maybe_object;
12227 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012228 FixedArray* instances = FixedArray::cast(object);
12229
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012230 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012231 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012232 HeapIterator heap_iterator2;
12233 count = DebugConstructedBy(&heap_iterator2,
12234 constructor,
12235 max_references,
12236 instances,
12237 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012238
12239 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012240 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012241 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12242 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012243 if (!maybe_result->ToObject(&result)) return maybe_result;
12244 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012245 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012246}
12247
12248
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012249// Find the effective prototype object as returned by __proto__.
12250// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012251RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012252 ASSERT(args.length() == 1);
12253
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012254 CONVERT_ARG_CHECKED(JSObject, obj, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012255
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012256 // Use the __proto__ accessor.
12257 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012258}
12259
12260
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000012261// Patches script source (should be called upon BeforeCompile event).
12262RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugSetScriptSource) {
12263 HandleScope scope(isolate);
12264 ASSERT(args.length() == 2);
12265
12266 CONVERT_ARG_HANDLE_CHECKED(JSValue, script_wrapper, 0);
12267 Handle<String> source(String::cast(args[1]));
12268
12269 RUNTIME_ASSERT(script_wrapper->value()->IsScript());
12270 Handle<Script> script(Script::cast(script_wrapper->value()));
12271
12272 int compilation_state = Smi::cast(script->compilation_state())->value();
12273 RUNTIME_ASSERT(compilation_state == Script::COMPILATION_STATE_INITIAL);
12274 script->set_source(*source);
12275
12276 return isolate->heap()->undefined_value();
12277}
12278
12279
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012280RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012281 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012282 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012283 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012284}
12285
12286
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012287RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012288#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012289 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012290 ASSERT(args.length() == 1);
12291 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012292 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012293 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012294 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012295 return Failure::Exception();
12296 }
12297 func->code()->PrintLn();
12298#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012299 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012300}
ager@chromium.org9085a012009-05-11 19:22:57 +000012301
12302
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012303RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012304#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012305 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012306 ASSERT(args.length() == 1);
12307 // Get the function and make sure it is compiled.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012308 CONVERT_ARG_HANDLE_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012309 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012310 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012311 return Failure::Exception();
12312 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012313 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012314#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012315 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012316}
12317
12318
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012319RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012320 NoHandleAllocation ha;
12321 ASSERT(args.length() == 1);
12322
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012323 CONVERT_ARG_CHECKED(JSFunction, f, 0);
ager@chromium.org9085a012009-05-11 19:22:57 +000012324 return f->shared()->inferred_name();
12325}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012326
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012327
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012328static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12329 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012330 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012331 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012332 int counter = 0;
12333 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012334 for (HeapObject* obj = iterator->next();
12335 obj != NULL;
12336 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012337 ASSERT(obj != NULL);
12338 if (!obj->IsSharedFunctionInfo()) {
12339 continue;
12340 }
12341 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12342 if (shared->script() != script) {
12343 continue;
12344 }
12345 if (counter < buffer_size) {
12346 buffer->set(counter, shared);
12347 }
12348 counter++;
12349 }
12350 return counter;
12351}
12352
12353// For a script finds all SharedFunctionInfo's in the heap that points
12354// to this script. Returns JSArray of SharedFunctionInfo wrapped
12355// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012356RUNTIME_FUNCTION(MaybeObject*,
12357 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012358 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012359 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012360 CONVERT_ARG_CHECKED(JSValue, script_value, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012361
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012362
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012363 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12364
12365 const int kBufferSize = 32;
12366
12367 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012368 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012369 int number;
12370 {
12371 isolate->heap()->EnsureHeapIsIterable();
12372 AssertNoAllocation no_allocations;
12373 HeapIterator heap_iterator;
12374 Script* scr = *script;
12375 FixedArray* arr = *array;
12376 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12377 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012378 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012379 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012380 isolate->heap()->EnsureHeapIsIterable();
12381 AssertNoAllocation no_allocations;
12382 HeapIterator heap_iterator;
12383 Script* scr = *script;
12384 FixedArray* arr = *array;
12385 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012386 }
12387
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012388 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012389 result->set_length(Smi::FromInt(number));
12390
12391 LiveEdit::WrapSharedFunctionInfos(result);
12392
12393 return *result;
12394}
12395
12396// For a script calculates compilation information about all its functions.
12397// The script source is explicitly specified by the second argument.
12398// The source of the actual script is not used, however it is important that
12399// all generated code keeps references to this particular instance of script.
12400// Returns a JSArray of compilation infos. The array is ordered so that
12401// each function with all its descendant is always stored in a continues range
12402// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012403RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012404 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012405 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012406 CONVERT_ARG_CHECKED(JSValue, script, 0);
12407 CONVERT_ARG_HANDLE_CHECKED(String, source, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012408 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12409
12410 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12411
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012412 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012413 return Failure::Exception();
12414 }
12415
12416 return result;
12417}
12418
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012419// Changes the source of the script to a new_source.
12420// If old_script_name is provided (i.e. is a String), also creates a copy of
12421// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012422RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012423 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012424 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012425 CONVERT_ARG_CHECKED(JSValue, original_script_value, 0);
12426 CONVERT_ARG_HANDLE_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012427 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012428
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012429 RUNTIME_ASSERT(original_script_value->value()->IsScript());
12430 Handle<Script> original_script(Script::cast(original_script_value->value()));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012431
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012432 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12433 new_source,
12434 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012435
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012436 if (old_script->IsScript()) {
12437 Handle<Script> script_handle(Script::cast(old_script));
12438 return *(GetScriptWrapper(script_handle));
12439 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012440 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012441 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012442}
12443
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012444
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012445RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012446 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012447 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012448 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012449 return LiveEdit::FunctionSourceUpdated(shared_info);
12450}
12451
12452
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012453// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012454RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012455 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012456 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012457 CONVERT_ARG_HANDLE_CHECKED(JSArray, new_compile_info, 0);
12458 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_info, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012459
ager@chromium.orgac091b72010-05-05 07:34:42 +000012460 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012461}
12462
12463// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012464RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012465 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012466 HandleScope scope(isolate);
12467 Handle<Object> function_object(args[0], isolate);
12468 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012469
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012470 if (function_object->IsJSValue()) {
12471 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12472 if (script_object->IsJSValue()) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012473 RUNTIME_ASSERT(JSValue::cast(*script_object)->value()->IsScript());
12474 Script* script = Script::cast(JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012475 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012476 }
12477
12478 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12479 } else {
12480 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12481 // and we check it in this function.
12482 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012483
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012484 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012485}
12486
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012487
12488// In a code of a parent function replaces original function as embedded object
12489// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012490RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012491 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012492 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012493
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012494 CONVERT_ARG_HANDLE_CHECKED(JSValue, parent_wrapper, 0);
12495 CONVERT_ARG_HANDLE_CHECKED(JSValue, orig_wrapper, 1);
12496 CONVERT_ARG_HANDLE_CHECKED(JSValue, subst_wrapper, 2);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012497
12498 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12499 subst_wrapper);
12500
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012501 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012502}
12503
12504
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012505// Updates positions of a shared function info (first parameter) according
12506// to script source change. Text change is described in second parameter as
12507// array of groups of 3 numbers:
12508// (change_begin, change_end, change_end_new_position).
12509// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012510RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012511 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012512 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012513 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12514 CONVERT_ARG_HANDLE_CHECKED(JSArray, position_change_array, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012515
ager@chromium.orgac091b72010-05-05 07:34:42 +000012516 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012517}
12518
12519
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012520// For array of SharedFunctionInfo's (each wrapped in JSValue)
12521// checks that none of them have activations on stacks (of any thread).
12522// Returns array of the same length with corresponding results of
12523// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012524RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012525 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012526 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012527 CONVERT_ARG_HANDLE_CHECKED(JSArray, shared_array, 0);
12528 CONVERT_BOOLEAN_ARG_CHECKED(do_drop, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012529
ager@chromium.org357bf652010-04-12 11:30:10 +000012530 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012531}
12532
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012533// Compares 2 strings line-by-line, then token-wise and returns diff in form
12534// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12535// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012536RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012537 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012538 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012539 CONVERT_ARG_HANDLE_CHECKED(String, s1, 0);
12540 CONVERT_ARG_HANDLE_CHECKED(String, s2, 1);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012541
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012542 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012543}
12544
12545
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012546// A testing entry. Returns statement position which is the closest to
12547// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012548RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012549 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012550 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012551 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012552 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12553
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012554 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012555
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012556 if (code->kind() != Code::FUNCTION &&
12557 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012558 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012559 }
12560
12561 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012562 int closest_pc = 0;
12563 int distance = kMaxInt;
12564 while (!it.done()) {
12565 int statement_position = static_cast<int>(it.rinfo()->data());
12566 // Check if this break point is closer that what was previously found.
12567 if (source_position <= statement_position &&
12568 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012569 closest_pc =
12570 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012571 distance = statement_position - source_position;
12572 // Check whether we can't get any closer.
12573 if (distance == 0) break;
12574 }
12575 it.next();
12576 }
12577
12578 return Smi::FromInt(closest_pc);
12579}
12580
12581
ager@chromium.org357bf652010-04-12 11:30:10 +000012582// Calls specified function with or without entering the debugger.
12583// This is used in unit tests to run code as if debugger is entered or simply
12584// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012585RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012586 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012587 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012588 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
12589 CONVERT_BOOLEAN_ARG_CHECKED(without_debugger, 1);
ager@chromium.org357bf652010-04-12 11:30:10 +000012590
12591 Handle<Object> result;
12592 bool pending_exception;
12593 {
12594 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012595 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012596 &pending_exception);
12597 } else {
12598 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012599 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012600 &pending_exception);
12601 }
12602 }
12603 if (!pending_exception) {
12604 return *result;
12605 } else {
12606 return Failure::Exception();
12607 }
12608}
12609
12610
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012611// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012612RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012613 CONVERT_ARG_CHECKED(String, arg, 0);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012614 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012615 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12616 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012617 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012618}
12619
12620
12621// Performs a GC.
12622// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012623RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000012624 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "%CollectGarbage");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012625 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012626}
12627
12628
12629// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012630RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012631 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012632 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012633 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012634 }
12635 return Smi::FromInt(usage);
12636}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012637
12638
12639// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012640RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012641#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012642 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012643#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012644 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012645#endif
12646}
12647
12648
12649// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012650RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012651#ifdef LIVE_OBJECT_LIST
12652 return LiveObjectList::Capture();
12653#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012654 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012655#endif
12656}
12657
12658
12659// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012660RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012661#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012662 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012663 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012664 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012665#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012666 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012667#endif
12668}
12669
12670
12671// Generates the response to a debugger request for a dump of the objects
12672// contained in the difference between the captured live object lists
12673// specified by id1 and id2.
12674// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12675// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012676RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012677#ifdef LIVE_OBJECT_LIST
12678 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012679 CONVERT_SMI_ARG_CHECKED(id1, 0);
12680 CONVERT_SMI_ARG_CHECKED(id2, 1);
12681 CONVERT_SMI_ARG_CHECKED(start, 2);
12682 CONVERT_SMI_ARG_CHECKED(count, 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012683 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012684 EnterDebugger enter_debugger;
12685 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12686#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012687 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012688#endif
12689}
12690
12691
12692// Gets the specified object as requested by the debugger.
12693// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012694RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012695#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012696 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012697 Object* result = LiveObjectList::GetObj(obj_id);
12698 return result;
12699#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012700 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012701#endif
12702}
12703
12704
12705// Gets the obj id for the specified address if valid.
12706// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012707RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012708#ifdef LIVE_OBJECT_LIST
12709 HandleScope scope;
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012710 CONVERT_ARG_HANDLE_CHECKED(String, address, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012711 Object* result = LiveObjectList::GetObjId(address);
12712 return result;
12713#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012714 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012715#endif
12716}
12717
12718
12719// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012720RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012721#ifdef LIVE_OBJECT_LIST
12722 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012723 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012724 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12725 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12726 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12727 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012728 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 5);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012729
12730 Handle<JSObject> instance_filter;
12731 if (args[1]->IsJSObject()) {
12732 instance_filter = args.at<JSObject>(1);
12733 }
12734 bool verbose = false;
12735 if (args[2]->IsBoolean()) {
12736 verbose = args[2]->IsTrue();
12737 }
12738 int start = 0;
12739 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012740 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012741 }
12742 int limit = Smi::kMaxValue;
12743 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012744 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012745 }
12746
12747 return LiveObjectList::GetObjRetainers(obj_id,
12748 instance_filter,
12749 verbose,
12750 start,
12751 limit,
12752 filter_obj);
12753#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012754 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012755#endif
12756}
12757
12758
12759// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012760RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012761#ifdef LIVE_OBJECT_LIST
12762 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012763 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12764 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012765 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12766
12767 Handle<JSObject> instance_filter;
12768 if (args[2]->IsJSObject()) {
12769 instance_filter = args.at<JSObject>(2);
12770 }
12771
12772 Object* result =
12773 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12774 return result;
12775#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012776 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012777#endif
12778}
12779
12780
12781// Generates the response to a debugger request for a list of all
12782// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012783RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012784#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012785 CONVERT_SMI_ARG_CHECKED(start, 0);
12786 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012787 return LiveObjectList::Info(start, count);
12788#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012789 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012790#endif
12791}
12792
12793
12794// Gets a dump of the specified object as requested by the debugger.
12795// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012796RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012797#ifdef LIVE_OBJECT_LIST
12798 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012799 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012800 Object* result = LiveObjectList::PrintObj(obj_id);
12801 return result;
12802#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012803 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012804#endif
12805}
12806
12807
12808// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012809RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012810#ifdef LIVE_OBJECT_LIST
12811 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012812 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012813#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012814 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012815#endif
12816}
12817
12818
12819// Generates the response to a debugger request for a summary of the types
12820// of objects in the difference between the captured live object lists
12821// specified by id1 and id2.
12822// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12823// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012824RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012825#ifdef LIVE_OBJECT_LIST
12826 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012827 CONVERT_SMI_ARG_CHECKED(id1, 0);
12828 CONVERT_SMI_ARG_CHECKED(id2, 1);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012829 CONVERT_ARG_HANDLE_CHECKED(JSObject, filter_obj, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012830
12831 EnterDebugger enter_debugger;
12832 return LiveObjectList::Summarize(id1, id2, filter_obj);
12833#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012834 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012835#endif
12836}
12837
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012838#endif // ENABLE_DEBUGGER_SUPPORT
12839
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012840
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012841RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012842 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012843 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012844 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012845}
12846
12847
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012848RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012849 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012850 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012851 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012852}
12853
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012854
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012855// Finds the script object from the script data. NOTE: This operation uses
12856// heap traversal to find the function generated for the source position
12857// for the requested break point. For lazily compiled functions several heap
12858// traversals might be required rendering this operation as a rather slow
12859// operation. However for setting break points which is normally done through
12860// some kind of user interaction the performance is not crucial.
12861static Handle<Object> Runtime_GetScriptFromScriptName(
12862 Handle<String> script_name) {
12863 // Scan the heap for Script objects to find the script with the requested
12864 // script data.
12865 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012866 script_name->GetHeap()->EnsureHeapIsIterable();
12867 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012868 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012869 HeapObject* obj = NULL;
12870 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012871 // If a script is found check if it has the script data requested.
12872 if (obj->IsScript()) {
12873 if (Script::cast(obj)->name()->IsString()) {
12874 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12875 script = Handle<Script>(Script::cast(obj));
12876 }
12877 }
12878 }
12879 }
12880
12881 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012882 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012883
12884 // Return the script found.
12885 return GetScriptWrapper(script);
12886}
12887
12888
12889// Get the script object from script data. NOTE: Regarding performance
12890// see the NOTE for GetScriptFromScriptData.
12891// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012892RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012893 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012894
12895 ASSERT(args.length() == 1);
12896
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012897 CONVERT_ARG_CHECKED(String, script_name, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012898
12899 // Find the requested script.
12900 Handle<Object> result =
12901 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12902 return *result;
12903}
12904
12905
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012906// Determines whether the given stack frame should be displayed in
12907// a stack trace. The caller is the error constructor that asked
12908// for the stack trace to be collected. The first time a construct
12909// call to this function is encountered it is skipped. The seen_caller
12910// in/out parameter is used to remember if the caller has been seen
12911// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012912static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12913 Object* caller,
12914 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012915 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012916 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012917 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012918 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012919 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12920 Object* raw_fun = frame->function();
12921 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012922 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012923 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012924 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012925 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012926 *seen_caller = true;
12927 return false;
12928 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012929 // Skip all frames until we've seen the caller.
12930 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012931 // Also, skip non-visible built-in functions and any call with the builtins
12932 // object as receiver, so as to not reveal either the builtins object or
12933 // an internal function.
12934 // The --builtins-in-stack-traces command line flag allows including
12935 // internal call sites in the stack trace for debugging purposes.
12936 if (!FLAG_builtins_in_stack_traces) {
12937 JSFunction* fun = JSFunction::cast(raw_fun);
12938 if (frame->receiver()->IsJSBuiltinsObject() ||
12939 (fun->IsBuiltin() && !fun->shared()->native())) {
12940 return false;
12941 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012942 }
12943 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012944}
12945
12946
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012947// Collect the raw data for a stack trace. Returns an array of 4
12948// element segments each containing a receiver, function, code and
12949// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012950RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000012951 ASSERT_EQ(args.length(), 3);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012952 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000012953 Handle<Object> caller = args.at<Object>(1);
12954 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012955
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012956 HandleScope scope(isolate);
12957 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012958
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012959 limit = Max(limit, 0); // Ensure that limit is not negative.
12960 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012961 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012962 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012963
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012964 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012965 // If the caller parameter is a function we skip frames until we're
12966 // under it before starting to collect.
12967 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012968 int cursor = 0;
12969 int frames_seen = 0;
12970 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012971 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012972 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012973 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012974 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012975 // Set initial size to the maximum inlining level + 1 for the outermost
12976 // function.
12977 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012978 frame->Summarize(&frames);
12979 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012980 if (cursor + 4 > elements->length()) {
12981 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12982 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012983 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012984 for (int i = 0; i < cursor; i++) {
12985 new_elements->set(i, elements->get(i));
12986 }
12987 elements = new_elements;
12988 }
12989 ASSERT(cursor + 4 <= elements->length());
12990
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012991 Handle<Object> recv = frames[i].receiver();
12992 Handle<JSFunction> fun = frames[i].function();
12993 Handle<Code> code = frames[i].code();
12994 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012995 elements->set(cursor++, *recv);
12996 elements->set(cursor++, *fun);
12997 elements->set(cursor++, *code);
12998 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012999 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013000 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013001 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013002 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013003 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013004 // Capture and attach a more detailed stack trace if necessary.
13005 isolate->CaptureAndSetCurrentStackTraceFor(error_object);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013006 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013007 return *result;
13008}
13009
13010
ager@chromium.org3811b432009-10-28 14:53:37 +000013011// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013012RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013013 ASSERT_EQ(args.length(), 0);
13014
13015 NoHandleAllocation ha;
13016
13017 const char* version_string = v8::V8::GetVersion();
13018
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013019 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13020 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013021}
13022
13023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013024RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013025 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013026 OS::PrintError("abort: %s\n",
13027 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013028 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013029 OS::Abort();
13030 UNREACHABLE();
13031 return NULL;
13032}
13033
13034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013035RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013036 // This is only called from codegen, so checks might be more lax.
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013037 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013038 Object* key = args[1];
13039
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013040 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013041 Object* o = cache->get(finger_index);
13042 if (o == key) {
13043 // The fastest case: hit the same place again.
13044 return cache->get(finger_index + 1);
13045 }
13046
13047 for (int i = finger_index - 2;
13048 i >= JSFunctionResultCache::kEntriesIndex;
13049 i -= 2) {
13050 o = cache->get(i);
13051 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013052 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013053 return cache->get(i + 1);
13054 }
13055 }
13056
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013057 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013058 ASSERT(size <= cache->length());
13059
13060 for (int i = size - 2; i > finger_index; i -= 2) {
13061 o = cache->get(i);
13062 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013063 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013064 return cache->get(i + 1);
13065 }
13066 }
13067
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013068 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013069 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013070
13071 Handle<JSFunctionResultCache> cache_handle(cache);
13072 Handle<Object> key_handle(key);
13073 Handle<Object> value;
13074 {
13075 Handle<JSFunction> factory(JSFunction::cast(
13076 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13077 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013078 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013079 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013080 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013081 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013082 value = Execution::Call(factory,
13083 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013084 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013085 argv,
13086 &pending_exception);
13087 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013088 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013089
13090#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013091 if (FLAG_verify_heap) {
13092 cache_handle->JSFunctionResultCacheVerify();
13093 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013094#endif
13095
13096 // Function invocation may have cleared the cache. Reread all the data.
13097 finger_index = cache_handle->finger_index();
13098 size = cache_handle->size();
13099
13100 // If we have spare room, put new data into it, otherwise evict post finger
13101 // entry which is likely to be the least recently used.
13102 int index = -1;
13103 if (size < cache_handle->length()) {
13104 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13105 index = size;
13106 } else {
13107 index = finger_index + JSFunctionResultCache::kEntrySize;
13108 if (index == cache_handle->length()) {
13109 index = JSFunctionResultCache::kEntriesIndex;
13110 }
13111 }
13112
13113 ASSERT(index % 2 == 0);
13114 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13115 ASSERT(index < cache_handle->length());
13116
13117 cache_handle->set(index, *key_handle);
13118 cache_handle->set(index + 1, *value);
13119 cache_handle->set_finger_index(index);
13120
13121#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013122 if (FLAG_verify_heap) {
13123 cache_handle->JSFunctionResultCacheVerify();
13124 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013125#endif
13126
13127 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013128}
13129
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013130
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013131RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013132 HandleScope scope(isolate);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013133 CONVERT_ARG_HANDLE_CHECKED(String, type, 0);
13134 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013135 return *isolate->factory()->NewJSMessageObject(
13136 type,
13137 arguments,
13138 0,
13139 0,
13140 isolate->factory()->undefined_value(),
13141 isolate->factory()->undefined_value(),
13142 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013143}
13144
13145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013146RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013147 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013148 return message->type();
13149}
13150
13151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013152RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013153 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013154 return message->arguments();
13155}
13156
13157
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013158RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013159 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013160 return Smi::FromInt(message->start_position());
13161}
13162
13163
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013164RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013165 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013166 return message->script();
13167}
13168
13169
kasper.lund44510672008-07-25 07:37:58 +000013170#ifdef DEBUG
13171// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13172// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013173RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013174 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013175 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013176#define COUNT_ENTRY(Name, argc, ressize) + 1
13177 int entry_count = 0
13178 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13179 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13180 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13181#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013182 Factory* factory = isolate->factory();
13183 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013184 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013185 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013186#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013187 { \
13188 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013189 Handle<String> name; \
13190 /* Inline runtime functions have an underscore in front of the name. */ \
13191 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013192 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013193 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13194 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013195 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013196 Vector<const char>(#Name, StrLength(#Name))); \
13197 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013198 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013199 pair_elements->set(0, *name); \
13200 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013201 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013202 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013203 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013204 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013205 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013206 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013207 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013208 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013209#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013210 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013211 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013212 return *result;
13213}
kasper.lund44510672008-07-25 07:37:58 +000013214#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013215
13216
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013217RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013218 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013219 CONVERT_ARG_CHECKED(String, format, 0);
13220 CONVERT_ARG_CHECKED(JSArray, elms, 1);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013221 String::FlatContent format_content = format->GetFlatContent();
13222 RUNTIME_ASSERT(format_content.IsAscii());
13223 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013224 LOGGER->LogRuntime(chars, elms);
13225 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013226}
13227
13228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013229RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013230 UNREACHABLE(); // implemented as macro in the parser
13231 return NULL;
13232}
13233
13234
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013235#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13236 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013237 CONVERT_ARG_CHECKED(JSObject, obj, 0); \
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013238 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13239 }
13240
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013241ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013242ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13243ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13244ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13245ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13246ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13247ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13248ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13249ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13250ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13251ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13252ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13253ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13254ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13255
13256#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13257
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013258
13259RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13260 ASSERT(args.length() == 2);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000013261 CONVERT_ARG_CHECKED(JSObject, obj1, 0);
13262 CONVERT_ARG_CHECKED(JSObject, obj2, 1);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013263 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13264}
13265
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013266// ----------------------------------------------------------------------------
13267// Implementation of Runtime
13268
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013269#define F(name, number_of_args, result_size) \
13270 { Runtime::k##name, Runtime::RUNTIME, #name, \
13271 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013272
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013273
13274#define I(name, number_of_args, result_size) \
13275 { Runtime::kInline##name, Runtime::INLINE, \
13276 "_" #name, NULL, number_of_args, result_size },
13277
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013278static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013279 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013280 INLINE_FUNCTION_LIST(I)
13281 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013282};
13283
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013284
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013285MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13286 Object* dictionary) {
13287 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013288 ASSERT(dictionary != NULL);
13289 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13290 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013291 Object* name_symbol;
13292 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013293 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013294 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13295 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013296 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013297 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13298 String::cast(name_symbol),
13299 Smi::FromInt(i),
13300 PropertyDetails(NONE, NORMAL));
13301 if (!maybe_dictionary->ToObject(&dictionary)) {
13302 // Non-recoverable failure. Calling code must restart heap
13303 // initialization.
13304 return maybe_dictionary;
13305 }
13306 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013307 }
13308 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013309}
13310
13311
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013312const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13313 Heap* heap = name->GetHeap();
13314 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013315 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013316 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013317 int function_index = Smi::cast(smi_index)->value();
13318 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013319 }
13320 return NULL;
13321}
13322
13323
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013324const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013325 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13326}
13327
13328
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013329void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013330 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013331 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013332 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013333 if (isolate->heap()->new_space()->AddFreshPage()) {
13334 return;
13335 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000013336
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013337 // Try to do a garbage collection; ignore it if it fails. The C
13338 // entry stub will throw an out-of-memory exception in that case.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013339 isolate->heap()->CollectGarbage(failure->allocation_space(),
13340 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013341 } else {
13342 // Handle last resort GC and make sure to allow future allocations
13343 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013344 isolate->counters()->gc_last_resort_from_js()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013345 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13346 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013347 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013348}
13349
13350
13351} } // namespace v8::internal